// ToolsLib Project

/* ToolsLib library for RusRoute firewall and other projects of
 * Andrey A. Moiseenko / IE Moiseenko A.A. (Russia)
 * e-mail: support@maasoftware.ru, maa2002@mail.ru
 * web: http://maasoftware.ru, http://maasoftware.com, http://maasoft.ru, http://maasoft.org
 * Author's full name: Andrey Alekseevitch Moiseenko
 * (russian name: Моисеенко Андрей Алексеевич)
 */

// ToolsLib/MaaTL.h

/* Copyright (C) 2002-2024 Andrey A. Moiseenko (support@maasoftware.ru)
 * All rights reserved.
 *
 * This library contains cross-platform templates for working with
 * linked lists, hash tables and so on. First dated at 16.10.2003.
 * The library implementation written
 * by Andrey A. Moiseenko (support@maasoftware.ru).
 * This library and applications are
 * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE
 * as long as the following conditions are aheared to.
 *
 * Copyright remains Andrey A. Moiseenko, and as such any Copyright notices in
 * the code are not to be removed.  If this code is used in a product,
 * Andrey A. Moiseenko should be given attribution as the author of the parts used.
 * This can be in the form of a textual message at program startup or
 * in documentation (online or textual) provided with the package.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by Andrey A. Moiseenko (support@maasoftware.ru)
 *
 * THIS SOFTWARE IS PROVIDED BY ANDREY A. MOISEENKO ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * The licence and distribution terms for any publically available version or
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
 * copied and put under another distribution licence
 * [including the GNU Public Licence.]
 */

#ifndef __MAARF_MAATL_H
#define __MAARF_MAATL_H

//#define TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE // auto squeeze CMaaUnivHash if h.SetAutoSqueeze(true) is called / TOOLSLIB_HT_DEF_FLAG == 1
//#define TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
//#define TOOLSLIB_SHARED_ALLOCATOR

#ifdef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
#define TOOLSLIB_HT_DEF_FLAG 0x04 // eAutoSqueeze
#else
#define TOOLSLIB_HT_DEF_FLAG 0x00
#endif

#if defined(TOOLSLIB_MAX_SPEED) && defined(TOOLSLIB_SINGLE_THREAD) && !defined(TOOLSLIB_SHARED_ALLOCATOR)
#define TOOLSLIB_SHARED_ALLOCATOR
#endif

#define TRY_HF_OPT // TRY_HF_OPT is faster with -flto, and slower without of -flto
#ifdef _WIN32
#define TRY_HF8_OPT
#endif
#ifdef __linux__
// If post defined "template <> _dword CMaaHashFunction<CMaaString>(const CMaaString & k) noexcept;", then
// TRY_HF8_OPT is slower by >3.2% (overall cms, linux x64).
// Inline post-defined "inline _dword CMaaHashFunction(const CMaaString & k) noexcept;" is sometimes solving this problem
//#define TRY_HF8_OPT
#endif

#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
#ifdef TOOLSLIB_SINGLE_THREAD
extern _qword gHashTablesAllocSize;
#else
extern std::atomic<_qword> gHashTablesAllocSize;
#endif
#endif

#ifndef TOOLSLIB_MAX_SPEED
#define __ALLOCATOR_FILL
#ifdef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
//#undef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
#endif
#endif
//#define __ALLOCATOR_RESERVE_PTR
#define __ALLOCATOR_FILL_INIT_CHAR 0xaa
#define __ALLOCATOR_FILL_ALLOC_CHAR 0xdd
#define __ALLOCATOR_FILL_FREE_CHAR 0xee

#define T_NULL(T) static_cast<T>(nullptr)

extern bool gbCMaaPtrThrow;

#ifndef _MaaRF_INTERNAL_BUILD
//#define Malloc(x) malloc(x)
//#define Free(x,y) free(x)
#define Memcpy(x,y,z) memcpy(x,y,z)
#define Memcmp(x,y,z) memcmp(x,y,z)
#define Memzero(x,y) memset(x,0,y)

#define Strlen(x) strlen(x)
#define Strcmp(x,y) strcmp(x,y)

#ifndef INT3
#define INT3
#endif
#ifndef CMaaPtr_THROW1
#define CMaaPtr_THROW1 throw "Memory allocation error"
#define CMaaPtr_THROW1_BAD_IMP throw "Bad implementation"
#endif
#ifndef CMaaPtr_THROW
#define CMaaPtr_THROW {if (gbCMaaPtrThrow) CMaaPtr_THROW1;}
#define CMaaPtr_THROW_BAD_IMP {if (gbCMaaPtrThrow) CMaaPtr_THROW1_BAD_IMP;}
#endif
#ifndef OUT_DEBUG_STRING
#define OUT_DEBUG_STRING(x)
#endif

#endif

#ifdef CMaaPtr_THROW
#define CMaaUnivHash_THROW CMaaPtr_THROW
#else
#define CMaaUnivHash_THROW {}
#endif

//---------------------------------------------------------------------------
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
template<class T> int CMaaXSign(T x) { return x < 0 ? -1 : x > 0 ? 1 : 0; }
//---------------------------------------------------------------------------
//template < class T > void CMaaSwap ( T & a, T & b ) noexcept(std::is_nothrow_move_constructible<T>::value && std::is_nothrow_move_assignable<T>::value)
template < class T > void CMaaSwap ( T & a, T & b )  noexcept( noexcept(T(a)) && noexcept(a=b) )
{
    T tmp ( a );
    a = b;
    b = tmp;
}
// noexcept( noexcept(CMaaSwap(a, a)) )
//---------------------------------------------------------------------------
struct CMaaDLink
{
    CMaaDLink * Next, * Prev; // list

    // it is not need to initialize links before caling AddAtXxxx ()
    void Init() noexcept
    {
        Prev = Next = nullptr;
    }
    void InsertAfter ( CMaaDLink * That ) noexcept  // .... That, this, ....
    {
        Next = That -> Next;
        Prev = That;
        Next -> Prev = this;
        That -> Next = this;
    }
    void InsertBefore ( CMaaDLink * That ) noexcept  // .... this, That, ....
    {
        Prev = That -> Prev;
        Next = That;
        Prev -> Next = this;
        That -> Prev = this;
    }
    CMaaDLink() noexcept
    {
        Init();
    }
} GCC_PACKED;
//---------------------------------------------------------------------------
template < class T > struct CMaaDLink_Item : public CMaaDLink
{
    T m_Item;
    operator T & () noexcept
    {
        return m_Item;
    }
};
//---------------------------------------------------------------------------
template < class T > struct CMaaDLink_pItem : public CMaaDLink
{
    T * m_pItem;
    operator T *& () noexcept
    {
        return m_pItem;
    }
    T * operator -> () noexcept
    {
        return m_pItem;
    }
    T * operator = ( T * ptr ) noexcept
    {
        return m_pItem = ptr;
    }
};
//---------------------------------------------------------------------------
template < class T > struct CMaaDLink_pItemAD : public CMaaDLink_pItem < T >
{
    CMaaDLink_pItemAD () noexcept
    {
        CMaaDLink_pItem < T >:: m_pItem = nullptr;
    }
    ~CMaaDLink_pItemAD () noexcept
    {
        delete CMaaDLink_pItem < T >:: m_pItem;
    }
    T * operator = ( T * ptr ) noexcept
    {
        return CMaaDLink_pItem < T >::operator = ( ptr );
    }
};
//---------------------------------------------------------------------------
template < class T > class CMaaDList
{
    CMaaDLink Head;
public:
    bool m_AutoDeleteItems;
    //----------------------------------------------------------------------
    CMaaDList ( bool AutoDeleteItems = false ) noexcept
    :   m_AutoDeleteItems ( AutoDeleteItems )
    {
        Init();
    }
    //----------------------------------------------------------------------
    /*virtual*/ ~CMaaDList() noexcept
    {
        if  ( m_AutoDeleteItems )
        {
            RemoveAll();
        }
    }
    //----------------------------------------------------------------------
    void Init() noexcept
    {
        Head.Prev = Head.Next = &Head;
    }
    bool IsEmpty () const noexcept
    {
        return Head.Next == &Head;
    }
    //----------------------------------------------------------------------
#ifndef __unix__
     //#define CMaaDLink__ CMaaDLink::
     #define CMaaDLink__
#else
     #define CMaaDLink__
#endif
    //----------------------------------------------------------------------
    //virtual void Delete ( T * p ) const noexcept
    //{
    //    delete p;
    //}
    //----------------------------------------------------------------------
    /*
    void Clear() noexcept
    {
        for (T* p; (p = GetFromFront()); )
        {
            Delete(p);
        }
    }
    */
    //----------------------------------------------------------------------
    void RemoveAll() noexcept
    {
        T* p;
        while ((p = GetFromFront()))
        {
            delete p;
        }
    }
    //----------------------------------------------------------------------
    void AddAtBack ( T * That ) noexcept
    {
        That -> CMaaDLink__ Prev = Head.Prev;
        That -> CMaaDLink__ Next = & Head;
        Head.Prev = That;
        That -> CMaaDLink__ Prev -> CMaaDLink__ Next = That;
    }
    //----------------------------------------------------------------------
    void AddAtFront ( T * That ) noexcept
    {
        That -> CMaaDLink__ Next = Head.Next;
        That -> CMaaDLink__ Prev = & Head;
        Head.Next = That;
        That -> CMaaDLink__ Next -> Prev = That;
    }
    //----------------------------------------------------------------------
    T * GetFromFront () noexcept
    {
        CMaaDLink * That;
        if  ( ( That = Head.Next ) == & Head )
        {
            That = nullptr;
        }
        else
        {
            That -> CMaaDLink__ Next -> Prev =  & Head;
            Head.Next = That -> CMaaDLink__ Next;
            That -> CMaaDLink__ Prev = That -> CMaaDLink__ Next = nullptr;
        }
        return ( T * ) That;
    }
    //----------------------------------------------------------------------
    T * GetFromBack () noexcept
    {
        CMaaDLink * That;
        if  ( ( That = Head.Prev ) == & Head )
        {
            That = nullptr;
        }
        else
        {
            That -> CMaaDLink__ Prev -> Next =  & Head;
            Head.Prev = That -> CMaaDLink__ Prev;
            That -> CMaaDLink__ Next = That -> CMaaDLink__ Prev = nullptr;
        }
        return ( T * ) That;
    }
    //----------------------------------------------------------------------
    T * LookAtFront () const noexcept
    {
        return ( Head.Next == &Head ) ? nullptr : ( T* ) Head.Next;
    }
    //----------------------------------------------------------------------
    T * LookAtBack () const noexcept
    {
        return ( Head.Prev == &Head ) ? nullptr : ( T* ) Head.Prev;
    }
    //----------------------------------------------------------------------
    T * Next ( T * That ) const noexcept
    {
        return That -> Next == & Head ? nullptr : ( T * ) That -> Next;
    }
    //----------------------------------------------------------------------
    T * Prev ( T * That ) const noexcept
    {
        return That -> Prev == & Head ? nullptr : ( T * ) That -> Prev;
    }
    //----------------------------------------------------------------------
    int CopyChainToBack ( T * pFirst, T * pSkip = nullptr ) noexcept
    {
        int Ret = 0;
        while ( pFirst )
        {
            CMaaDLink * pThis = pFirst;
            pFirst = ( T * ) pFirst -> CMaaDLink__ Next;
            if  ( pThis != pSkip )
            {
                AddAtBack ( ( T * ) pThis );
            }
            else
            {
                pThis->Init();
                Ret++;
            }
        }
        return Ret;
    }
    //----------------------------------------------------------------------
    static void Release ( T * That ) noexcept
    {
        if  ( That -> CMaaDLink__ Prev )
        {
            That -> CMaaDLink__ Prev -> Next = That -> CMaaDLink__ Next;
        }
        else
        {
            INT3 // I never pass here free item
        }
        if  ( That -> CMaaDLink__ Next )
        {
            That -> CMaaDLink__ Next -> Prev = That -> CMaaDLink__ Prev;
        }
        else
        {
            INT3 // I never pass here free item
        }
        That -> CMaaDLink__ Next = That -> CMaaDLink__ Prev = nullptr; // but it is not nessesary to perform initializations
    }
    //----------------------------------------------------------------------
    static void ReleaseSafe ( T * That ) noexcept
    {
        if  ( That -> CMaaDLink__ Prev )
        {
            That -> CMaaDLink__ Prev -> Next = That -> CMaaDLink__ Next;
        }
        else
        {
            // safe
        }
        if  ( That -> CMaaDLink__ Next )
        {
            That -> CMaaDLink__ Next -> Prev = That -> CMaaDLink__ Prev;
        }
        else
        {
            // safe
        }
        That -> CMaaDLink__ Next = That -> CMaaDLink__ Prev = nullptr; // but it is not nessesary to perform initializations
    }
    //----------------------------------------------------------------------
#if 0
    void Remove(T* That) noexcept
    {
        Release ( That );
    }
#endif
    //----------------------------------------------------------------------
    //static void InsertAfrer ( T * That, T * After )
    //{
    //     That -> CMaaDLink__ Next = After -> CMaaDLink__ Next;
    //     That -> CMaaDLink__ Prev = After;
    //     That -> CMaaDLink__ Next -> Prev = That;
    //}
    //----------------------------------------------------------------------
    int GetCount () const noexcept
    {
        int c = 0;
        T * p;
        for ( p = LookAtFront (); p; p = this->Next ( p ) )
        {
            c++;
        }
        return c;
    }
    int GetItemCount() const noexcept {return GetCount();}
    void MoveThatToTheEnd ( CMaaDList < T > & That ) noexcept
    {
        if  ( !That.IsEmpty () )
        {
            T * F = ( T * ) That.Head.Next;
            T * L = ( T * ) That.Head.Prev;
            T * m = ( T * ) Head.Prev;
            m -> Next = F;
            F -> Prev = m;
            L -> Next = &Head;
            Head.Prev = L;
            That.Init();
        }
    }
    void MoveThatToTheFront ( CMaaDList < T > & That ) noexcept
    {
        if  ( !That.IsEmpty () )
        {
            T * F = ( T * ) That.Head.Next;
            T * L = ( T * ) That.Head.Prev;
            T * m = ( T * ) Head.Next;
            m -> Prev = L;
            L -> Next = m;
            F -> Prev = &Head;
            Head.Next = F;
            That.Init();
        }
    }
    bool MoveUp ( T * That ) noexcept
    {
        T * Neighbor = Prev ( That );
        if  ( !Neighbor )
        {
            return false;
        }
        Release ( That );
        That -> InsertBefore ( Neighbor );
        return true;
    }
    bool MoveDown ( T * That ) noexcept
    {
        T * Neighbor = Next ( That );
        if  ( !Neighbor )
        {
            return false;
        }
        Release ( That );
        That -> InsertAfter ( Neighbor );
        return true;
    }
    void Swap(CMaaDList < T >& That, bool bAdSwap = false) noexcept
    {
        CMaaDList < T > tmp;
        tmp.MoveThatToTheFront(That);
        That.MoveThatToTheFront(*this);
        MoveThatToTheFront(tmp);
        if (bAdSwap)
        {
            CMaaSwap(m_AutoDeleteItems, That.m_AutoDeleteItems);
        }
    }
#undef CMaaDLink__
};
//---------------------------------------------------------------------------
template < class T > class CMaaDListAD : public CMaaDList < T >
{
public:
    CMaaDListAD () noexcept
    :   CMaaDList < T > ( true ) // Auto deleting list items from destructor by default
    {
    }
};

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
struct CMaaSLink
{
    CMaaSLink* Next; // s-list

    // it is not need to initialize links before caling AddAtXxxx ()
    void Init() noexcept
    {
        Next = nullptr;
    }
    /*
    void InsertAfter(CMaaSLink* That) noexcept  // .... That, this, ....
    {
        Next = That->Next;
        That->Next = this;
    }
    */
    /*
    --
    void InsertBefore(CMaaSLink* That) noexcept  // .... this, That, ....
    {
        //--// Next = That;
        //--// That->Next = this;
    }
    */
    CMaaSLink() noexcept
    {
        Init();
    }
} GCC_PACKED;
//---------------------------------------------------------------------------
template < class T > struct CMaaSLink_Item : public CMaaSLink
{
    T m_Item;
    operator T& () noexcept
    {
        return m_Item;
    }
};
//---------------------------------------------------------------------------
template < class T > struct CMaaSLink_pItem : public CMaaSLink
{
    T* m_pItem;
    operator T*& () noexcept
    {
        return m_pItem;
    }
    T* operator -> () noexcept
    {
        return m_pItem;
    }
    T* operator = (T* ptr) noexcept
    {
        return m_pItem = ptr;
    }
};
//---------------------------------------------------------------------------
template < class T > struct CMaaSLink_pItemAD : public CMaaSLink_pItem < T >
{
    CMaaSLink_pItemAD() noexcept
    {
        CMaaSLink_pItem < T >::m_pItem = nullptr;
    }
    ~CMaaSLink_pItemAD() noexcept
    {
        delete CMaaSLink_pItem < T >::m_pItem;
    }
    T* operator = (T* ptr) noexcept
    {
        return CMaaSLink_pItem < T >::operator = (ptr);
    }
};
//---------------------------------------------------------------------------
template < class T > class CMaaSList
{
    CMaaSLink Head;
public:
    bool m_AutoDeleteItems;
    //----------------------------------------------------------------------
    CMaaSList(bool AutoDeleteItems = false) noexcept
    :   m_AutoDeleteItems(AutoDeleteItems)
    {
    }
    //----------------------------------------------------------------------
    /*virtual*/ ~CMaaSList() noexcept
    {
        if (m_AutoDeleteItems)
        {
            RemoveAll();
        }
    }
    //----------------------------------------------------------------------
    void Init() noexcept
    {
        Head.Next = nullptr;
    }
    bool IsEmpty() const noexcept
    {
        return !Head.Next;
    }
    //----------------------------------------------------------------------
#ifndef __unix__
//#define CMaaSLink__ CMaaSLink::
#define CMaaSLink__
#else
#define CMaaSLink__
#endif
    //----------------------------------------------------------------------
    void RemoveAll() noexcept
    {
        T* p;
        while ((p = GetFromFront()))
        {
            delete p;
        }
    }
    //----------------------------------------------------------------------
    void AddAtFront(T* That) noexcept
    {
        That->CMaaSLink__ Next = Head.Next;
        Head.Next = That;
    }
    //----------------------------------------------------------------------
    // That is free, After is in list
    static void InsertAfter(CMaaSLink* That, CMaaSLink* After) noexcept  // .... this, That, ....
    {
        That->CMaaSLink__ Next = After->CMaaSLink__ Next;
        After->CMaaSLink__ Next = That;
    }
    //----------------------------------------------------------------------
    T* GetFromFront() noexcept
    {
        CMaaSLink* That = Head.Next;
        if (That)
        {
            Head.Next = That->CMaaSLink__ Next;
            That->CMaaSLink__ Next = nullptr;
        }
        return (T*)That;
    }
    //----------------------------------------------------------------------
    T* LookAtFront() const noexcept
    {
        return (T*)Head.Next;
    }
    //----------------------------------------------------------------------
    static T* Next(T* That) noexcept
    {
        return (T*)That->CMaaSLink__ Next;
    }
    //----------------------------------------------------------------------
    T* ExtractChain() noexcept
    {
        T* Ret = LookAtFront();
        Init();
        return Ret;
    }
    //----------------------------------------------------------------------
    int GetCount() const noexcept
    {
        int c = 0;
        T* p;
        for (p = LookAtFront(); p; p = this->Next(p))
        {
            c++;
        }
        return c;
    }
    int GetItemCount() const noexcept { return GetCount(); }
    void Swap(CMaaSList < T >& That, bool bAdSwap = false) noexcept
    {
        CMaaSwap(Head.Next, That.Head.Next);
        if (bAdSwap)
        {
            CMaaSwap(m_AutoDeleteItems, That.m_AutoDeleteItems);
        }
    }
#undef CMaaSLink__
};
//---------------------------------------------------------------------------
template < class T > class CMaaSListAD : public CMaaSList < T >
{
public:
    CMaaSListAD() noexcept
    :   CMaaSList < T >(true) // Auto deleting list items from destructor by default
    {
    }
};

//---------------------------------------------------------------------------
// CMaaSList2 with tail access and insert, 2 links
//---------------------------------------------------------------------------
template < class T > class CMaaSList2
{
    CMaaSLink Head, Tail;
public:
    bool m_AutoDeleteItems;
    //----------------------------------------------------------------------
    CMaaSList2(bool AutoDeleteItems = false) noexcept
        : m_AutoDeleteItems(AutoDeleteItems)
    {
    }
    //----------------------------------------------------------------------
    /*virtual*/ ~CMaaSList2() noexcept
    {
        if (m_AutoDeleteItems)
        {
            RemoveAll();
        }
    }
    //----------------------------------------------------------------------
    void Init() noexcept
    {
        Tail.Next = Head.Next = nullptr;
    }
    bool IsEmpty() const noexcept
    {
        return !Head.Next;
    }
    //----------------------------------------------------------------------
#ifndef __unix__
//#define CMaaSLink__ CMaaSLink::
#define CMaaSLink__
#else
#define CMaaSLink__
#endif
    //----------------------------------------------------------------------
    void RemoveAll() noexcept
    {
        T* p;
        while ((p = GetFromFront()))
        {
            delete p;
        }
    }
    //----------------------------------------------------------------------
    void AddAtBack(T* That) noexcept
    {
        if (Tail.Next)
        {
            // >= 1 elements exists
            Tail.Next = Tail.Next->Next = That;
            That->CMaaSLink__ Next = nullptr;
        }
        else
        {
            // empty list
            Tail.Next = Head.Next = That;
            That->CMaaSLink__ Next = nullptr;
        }
    }
    //----------------------------------------------------------------------
    void AddAtFront(T* That) noexcept
    {
        if (Head.Next)
        {
            That->CMaaSLink__ Next = Head.Next;
            Head.Next = That;
        }
        else
        {
            // empty list
            Tail.Next = Head.Next = That;
            That->CMaaSLink__ Next = nullptr;
        }
    }
    //----------------------------------------------------------------------
    // That is free, After is in list
    void InsertAfter(CMaaSLink* That, CMaaSLink* After) noexcept  // .... this, That, ....
    {
        That->CMaaSLink__ Next = After->CMaaSLink__ Next;
        After->CMaaSLink__ Next = That;
        if (Tail.Next == After)
        {
            Tail.Next = That;
        }
    }
    //----------------------------------------------------------------------
    T* GetFromFront() noexcept
    {
        CMaaSLink* That = Head.Next;
        if (That)
        {
            if (!(Head.Next = That->CMaaSLink__ Next))
            {
                Tail.Next = nullptr;
            }
            That->CMaaSLink__ Next = nullptr;
        }
        return (T*)That;
    }
    //----------------------------------------------------------------------
    T* LookAtFront() const noexcept
    {
        return (T*)Head.Next;
    }
    //----------------------------------------------------------------------
    T* LookAtBack() const noexcept
    {
        return (T*)Tail.Next;
    }
    //----------------------------------------------------------------------
    static T* Next(T* That) noexcept
    {
        return (T*)That->CMaaSLink__ Next;
    }
    //----------------------------------------------------------------------
    T* ExtractChain() noexcept
    {
        T* Ret = LookAtFront();
        Init();
        return Ret;
    }
    //----------------------------------------------------------------------
    int CopyChainToBack(T* pFirst, T* pSkip = nullptr) noexcept
    {
        int Ret = 0;
        while ( pFirst )
        {
            CMaaSLink* pThis = pFirst;
            pFirst = (T*)pFirst->CMaaSLink__ Next;
            if (pThis != pSkip)
            {
                AddAtBack((T*)pThis);
            }
            else
            {
                pThis->Init();
                Ret++;
            }
        }
        return Ret;
    }
    //----------------------------------------------------------------------
    void ReleaseSlow(T* pThat) noexcept
    {
        T* c = ExtractChain();
        CopyChainToBack(c, pThat);
    }
    //----------------------------------------------------------------------
    int GetCount() const noexcept
    {
        int c = 0;
        T* p;
        for (p = LookAtFront(); p; p = this->Next(p))
        {
            c++;
        }
        return c;
    }
    int GetItemCount() const noexcept { return GetCount(); }
    void MoveThatToTheEnd(CMaaSList2 < T >& That) noexcept
    {
        if (!That.IsEmpty())
        {
            if (IsEmpty())
            {
                Head.Next = That.Head.Next;
                Tail.Next = That.Tail.Next;
            }
            else
            {
                Tail.Next->CMaaSLink__ Next = That.Head.Next;
                Tail.Next = That.Tail.Next;
            }
            That.Init();
        }
    }
    void MoveThatToTheFront(CMaaSList2 < T >& That) noexcept
    {
        if (!That.IsEmpty())
        {
            if (IsEmpty())
            {
                Head.Next = That.Head.Next;
                Tail.Next = That.Tail.Next;
            }
            else
            {
                That.Tail.Next->CMaaSLink__ Next = Head.Next;
                Head.Next = That.Head.Next;
            }
            That.Init();
        }
    }
    void Swap(CMaaSList2 < T >& That, bool bAdSwap = false) noexcept
    {
        CMaaSList2 < T > tmp;
        tmp.MoveThatToTheFront(That);
        That.MoveThatToTheFront(*this);
        MoveThatToTheFront(tmp);
        if (bAdSwap)
        {
            CMaaSwap(m_AutoDeleteItems, That.m_AutoDeleteItems);
        }
    }
#undef CMaaSLink__
};
//---------------------------------------------------------------------------
template < class T > class CMaaSList2AD : public CMaaSList2 < T >
{
public:
    CMaaSList2AD() noexcept
    :   CMaaSList2 < T >(true) // Auto deleting list items from destructor by default
    {
    }
};

//---------------------------------------------------------------------------
// CMaaSList2 with tail access and insert, 1 link
//---------------------------------------------------------------------------
template < class T > class CMaaSList1
{
    CMaaSLink Tail;
public:
    bool m_AutoDeleteItems;
    //----------------------------------------------------------------------
    CMaaSList1(bool AutoDeleteItems = false) noexcept
    :   m_AutoDeleteItems(AutoDeleteItems)
    {
    }
    //----------------------------------------------------------------------
    /*virtual*/ ~CMaaSList1() noexcept
    {
        if (m_AutoDeleteItems)
        {
            RemoveAll();
        }
    }
    //----------------------------------------------------------------------
    void Init() noexcept
    {
        Tail.Next = nullptr;
    }
    bool IsEmpty() const noexcept
    {
        return !Tail.Next;
    }
    //----------------------------------------------------------------------
#ifndef __unix__
//#define CMaaSLink__ CMaaSLink::
#define CMaaSLink__
#else
#define CMaaSLink__
#endif
    //----------------------------------------------------------------------
    void RemoveAll() noexcept
    {
        T* p;
        while ((p = GetFromFront()))
        {
            delete p;
        }
    }
    //----------------------------------------------------------------------
    void AddAtBack(T* That) noexcept
    {
        if (Tail.Next)
        {
            // >= 1 elements exists
            That->CMaaSLink__ Next = Tail.Next->Next;
            Tail.Next = Tail.Next->Next = That;
        }
        else
        {
            // empty list
            Tail.Next = That;
            That->CMaaSLink__ Next = That;
        }
    }
    //----------------------------------------------------------------------
    void AddAtFront(T* That) noexcept
    {
        if (Tail.Next)
        {
            That->CMaaSLink__ Next = Tail.Next->Next;
            Tail.Next->Next = That;
        }
        else
        {
            // empty list
            Tail.Next = That;
            That->CMaaSLink__ Next = That;
        }
    }
    //----------------------------------------------------------------------
    // That is free, After is in list
    void InsertAfter(CMaaSLink* That, CMaaSLink* After) noexcept  // .... this, That, ....
    {
        That->CMaaSLink__ Next = After->CMaaSLink__ Next;
        After->CMaaSLink__ Next = That;
        if (Tail.Next == After)
        {
            Tail.Next = That;
        }
    }
    //----------------------------------------------------------------------
    T* GetFromFront() noexcept
    {
        if (Tail.Next)
        {
            CMaaSLink * That = Tail.Next->Next;
            if (That->CMaaSLink__ Next == That)
            {
                Tail.Next = nullptr;
            }
            else
            {
                Tail.Next->Next = That->CMaaSLink__ Next;
            }
            That->CMaaSLink__ Next = nullptr;
            return (T*)That;
        }
        return (T*)nullptr;
    }
    //----------------------------------------------------------------------
    T* LookAtFront() const noexcept
    {
        return Tail.Next ? (T*)Tail.Next->Next : nullptr;
    }
    //----------------------------------------------------------------------
    T* LookAtBack() const noexcept
    {
        return (T*)Tail.Next;
    }
    //----------------------------------------------------------------------
    T* Next(T* That) const noexcept
    {
        return That->CMaaSLink__ Next != Tail.Next->Next ? (T*)That->CMaaSLink__ Next : nullptr;
    }
    //----------------------------------------------------------------------
    T* ExtractChain() noexcept
    {
        T* Ret = LookAtFront();
        if (Ret)
        {
            Tail.Next->CMaaSLink__ Next = nullptr;
        }
        Init();
        return Ret;
    }
    //----------------------------------------------------------------------
    int CopyChainToBack(T* pFirst, T* pSkip = nullptr) noexcept
    {
        int Ret = 0;
        while ( pFirst )
        {
            CMaaSLink* pThis = pFirst;
            pFirst = (T*)pFirst->CMaaSLink__ Next;
            if (pThis != pSkip)
            {
                AddAtBack((T*)pThis);
            }
            else
            {
                pThis->Init();
                Ret++;
            }
        }
        return Ret;
    }
    //----------------------------------------------------------------------
    void ReleaseSlow(T* pThat) noexcept
    {
        T* c = ExtractChain();
        CopyChainToBack(c, pThat);
    }
    //----------------------------------------------------------------------
    int GetCount() const noexcept
    {
        int c = 0;
        T* p;
        for (p = LookAtFront(); p; p = this->Next(p))
        {
            c++;
        }
        return c;
    }
    int GetItemCount() const noexcept { return GetCount(); }
    void MoveThatToTheEnd(CMaaSList1 < T >& That) noexcept
    {
        if (!That.IsEmpty())
        {
            if (IsEmpty())
            {
                Tail.Next = That.Tail.Next;
            }
            else
            {
                CMaaSLink * F = Tail.Next->CMaaSLink__ Next;
                Tail.Next->CMaaSLink__ Next = That.Tail.Next->CMaaSLink__ Next;
                That.Tail.Next->CMaaSLink__ Next = F;
                Tail.Next = That.Tail.Next;
            }
            That.Init();
        }
    }
    void MoveThatToTheFront(CMaaSList1 < T >& That) noexcept
    {
        if (!That.IsEmpty())
        {
            if (IsEmpty())
            {
                Tail.Next = That.Tail.Next;
            }
            else
            {
                CMaaSLink * m = That.Tail.Next->CMaaSLink__ Next;
                That.Tail.Next->CMaaSLink__ Next = Tail.Next->CMaaSLink__ Next;
                Tail.Next->CMaaSLink__ Next = m;
            }
            That.Init();
        }
    }
    void Swap(CMaaSList1 < T >& That, bool bAdSwap = false) noexcept
    {
        CMaaSList1 < T > tmp;
        tmp.MoveThatToTheFront(That);
        That.MoveThatToTheFront(*this);
        MoveThatToTheFront(tmp);
        if (bAdSwap)
        {
            CMaaSwap(m_AutoDeleteItems, That.m_AutoDeleteItems);
        }
    }
#undef CMaaSLink__
};
//---------------------------------------------------------------------------
template < class T > class CMaaSList1AD : public CMaaSList1 < T >
{
public:
    CMaaSList1AD() noexcept
    :   CMaaSList1 < T >(true) // Auto deleting list items from destructor by default
    {
    }
};

//---------------------------------------------------------------------------
#if 1
//---------------------------------------------------------------------------
// old version of CMaaPtr, CMaaPtrAE is faster
//---------------------------------------------------------------------------
template < class T > class CMaaPtr
{
protected:
    T* m_Ptr;
    int m_MaxIndex, m_TotalItems;
    int m_xThrow;

public:

    int GetThrowParameter() const noexcept
    {
        return m_xThrow;
    }
    void Swap(CMaaPtr& That) noexcept
    {
        CMaaSwap(m_Ptr, That.m_Ptr);
        CMaaSwap(m_MaxIndex, That.m_MaxIndex);
        CMaaSwap(m_xThrow, That.m_xThrow);
        CMaaSwap(m_TotalItems, That.m_TotalItems);
    }
    // This constructor creates MaxIndex numbers of elements of class T.
    // Under Windows makes exeption if no free memory available.
    CMaaPtr(CMaaPtr& x)
    :   m_Ptr(nullptr),
        m_MaxIndex(0),
        m_TotalItems(0),
        m_xThrow(x.m_xThrow)
    {
        CMaaPtr<T> tmp(x.m_MaxIndex, x.m_xThrow);
        if  (tmp.IsValid())
        {
            //memcpy(tmp, x, x.MaxIndex() * sizeof(T));
            int m = (int)x.m_MaxIndex;
            for (int i = 0; i < m; i++)
            {
                tmp.m_Ptr[i] = x.m_Ptr[i];
            }
        }
        tmp.Swap(*this);
    }

    void operator += (const CMaaPtr& x)
    {
        CMaaPtr<T> tmp((size_t)m_MaxIndex + (size_t)x.m_MaxIndex, m_xThrow);
        if  (tmp.IsValid())
        {
            //          memcpy(tmp, *this, MaxIndex() * sizeof(T));
            int i, m = (int)m_MaxIndex;
            for (i = 0; i < m; i++)
            {
                tmp.m_Ptr[i] = m_Ptr[i];
            }
            //          memcpy(MaxIndex + tmp, x, x.MaxIndex() * sizeof(T));
            int m2 = (int)x.m_MaxIndex;
            for (i = 0; i < m2; i++)
            {
                tmp.m_Ptr[i + m] = x.m_Ptr[i];
            }
        }
        tmp.Swap(*this);
    }

    void operator += (const T& x)
    {
        int m = (int)m_MaxIndex;
        if (CheckExpand(m + 1))
        {
            // m_MaxIndex === m + 1;
            if constexpr (noexcept(m_Ptr[m] = x))
            {
                m_Ptr[m] = x;
            }
            else
            {
                m_MaxIndex = m;
                m_Ptr[m] = x; // throwable
                m_MaxIndex = m + 1;
            }
            //return true;
        }
        //return false;
    }

    void operator += (T& x)
    {
        int m = (int)m_MaxIndex;
        if (CheckExpand(m + 1))
        {
            // m_MaxIndex === m + 1;
            if constexpr (noexcept(m_Ptr[m] = x))
            {
                m_Ptr[m] = x;
            }
            else
            {
                m_MaxIndex = m;
                m_Ptr[m] = x; // throwable
                m_MaxIndex = m + 1;
            }
            //return true;
        }
        //return false;
    }

    CMaaPtr<T>& operator = (const CMaaPtr<T>& That)
    {
        CMaaPtr<T> tmp(That.m_MaxIndex, m_xThrow);
        if  (tmp.IsValid())
        {
            int m = (int)That.m_MaxIndex;
            for (int i = 0; i < m; i++)
            {
                tmp.m_Ptr[i] = That.m_Ptr[i];
            }
        }
        tmp.Swap(*this);
        return *this;
    }

    void append(T x)
    {
        int m = (int)m_MaxIndex;
        if (CheckExpand(m + 1))
        {
            // m_MaxIndex === m + 1;
            if constexpr (noexcept(m_Ptr[m] = x))
            {
                m_Ptr[m] = x;
            }
            else
            {
                m_MaxIndex = m;
                m_Ptr[m] = x; // throwable
                m_MaxIndex = m + 1;
            }
            //return true;
        }
        //return false;
    }

    CMaaPtr(size_t MaxIndex = 0, int xThrow = 0)
    :   m_Ptr(nullptr),
        m_MaxIndex((int)MaxIndex),
        m_TotalItems((int)MaxIndex),
        m_xThrow(xThrow)
    {
        if  (MaxIndex)
        {
            try
            {
                m_Ptr = MaxIndex < INT_MAX && MaxIndex < SIZE_MAX / sizeof(T) ? TL_NEW T[MaxIndex] : nullptr;
            }
            catch(...)
            {
            }
            if  (!m_Ptr && MaxIndex)
            {
                INT3;
#ifndef __unix__
                OUT_DEBUG_STRING("MAARF:Memory allocation failed\r\n");
#endif
                m_MaxIndex = 0;
                m_TotalItems = m_TotalItems ? m_TotalItems : 1;
                if  (xThrow > 0)
                {
                    CMaaPtr_THROW1;
                }
                if  (xThrow == 0)
                {
                    CMaaPtr_THROW;
                }
            }
        }
    }

    virtual bool CheckResize(size_t MaxN) // MaxN - TL_NEW items count required
    {
        if (IsValid() && MaxN <= (size_t)m_TotalItems)
        {
            if ((int)MaxN > m_MaxIndex)
            {
                m_MaxIndex = (int)MaxN;
            }
            return true;
        }
        const size_t N = 2 * (size_t)m_TotalItems >= MaxN ? 2 * (size_t)m_TotalItems : MaxN;
        CMaaPtr<T> m2(N, m_xThrow);
        if (!m2.IsValid())
        {
            return false;
        }
        m2.m_MaxIndex = (int)MaxN;
        Swap(m2);
        return true;
    }

    virtual bool CheckExpand(size_t MaxN) // MaxN - TL_NEW items count required
    {
        if (IsValid() && MaxN <= (size_t)m_TotalItems)
        {
            if ((int)MaxN > m_MaxIndex)
            {
                m_MaxIndex = (int)MaxN;
            }
            return true;
        }
        const size_t N = 2 * (size_t)m_TotalItems >= MaxN ? 2 * (size_t)m_TotalItems : MaxN;
        CMaaPtr<T> m2(N, m_xThrow);
        if (!m2.IsValid())
        {
            return false;
        }
        int m = (int)m_MaxIndex;
        for (int i = 0; i < m; i++)
        {
            m2.m_Ptr[i] = m_Ptr[i];
        }
        m2.m_MaxIndex = (int)MaxN;
        Swap(m2);
        return true;
    }

    virtual ~CMaaPtr() noexcept
    {
        delete[] m_Ptr;
    }

    virtual bool IsValid() const noexcept
    {
        return m_Ptr || !m_TotalItems;
    }

    void Empty() noexcept
    {
        m_MaxIndex = 0;

        if (!IsValid())
        {
            m_TotalItems = 0;
        }
    }

    operator T* () noexcept
    {
        return m_Ptr;
    }

    T& operator * () const noexcept
    {
        return *m_Ptr;
    }

    T& operator [] (int Index) noexcept
    {
        return m_Ptr[Index];
    }
    const T& operator [] (int Index) const noexcept
    {
        return m_Ptr[Index];
    }
    T& at(int Index) noexcept
    {
        return m_Ptr[Index];
    }
    const T& at(int Index) const noexcept
    {
        return m_Ptr[Index];
    }
    size_t MaxIndex() const noexcept
    {
        return m_MaxIndex;
    }
    int count() const noexcept
    {
        return (int)m_MaxIndex;
    }
    int size() const noexcept
    {
        return (int)MaxIndex();
    }
    size_t Size() const noexcept
    {
        return m_MaxIndex * sizeof(T);
    }
    void Zero() noexcept
    {
        if  (m_Ptr)
        {
            Memzero(m_Ptr, (size_t)sizeof(T) * m_MaxIndex);
        }
    }
    void fill(const T& value, int size = -1)
    {
        if  (m_Ptr && size <= (int)m_MaxIndex)
        {
            for (int i = 0; i < size; i++)
            {
                m_Ptr[i] = value;
            }
        }
    }
    virtual bool Resize(int n)
    {
        CMaaPtr < T > tmp(n, m_xThrow);
        if  (!tmp.IsValid())
        {
            return false;
        }
        const int nn = (int)m_MaxIndex < n ? (int)m_MaxIndex : n;
        for (int i = 0; i < nn; i++)
        {
            tmp[i] = (*this)[i];
        }
        Swap(tmp);
        return true;
    }
    int Get_xThrow() const noexcept
    {
        return m_xThrow;
    }
    bool resize(int n)
    {
        CMaaPtr < T > tmp(n, m_xThrow);
        if  (!tmp.IsValid())
        {
            return false;
        }
        /*
        int nn = (int)m_MaxIndex < n ? (int)m_MaxIndex : n;
        for (int i = 0; i < nn; i++)
        {
            tmp[i] = (*this)[i];
        }
        */
        //tmp.MaxIndex = nn;
        Swap(tmp);
        return true;
    }
    static void Delete(T* ptr) noexcept
    {
        delete[] ptr;
    }
    T* Extract() noexcept
    {
        T* ptr = m_Ptr;
        m_Ptr = nullptr;
        return ptr;
    }
};
//---------------------------------------------------------------------------
// Automatic expandable CMaaPtr
template < class T > class CMaaPtrAE : public CMaaPtr < T >
{
public:
    CMaaPtrAE(size_t MaxIndex, int xThrow = 0)
    :   CMaaPtr < T >(MaxIndex, xThrow)
    {
    }
    CMaaPtrAE(CMaaPtrAE<T>& That)
    :   CMaaPtr < T >(That.m_MaxIndex, That.m_xThrow)
    {
        if  (CMaaPtr < T >::IsValid() && That.IsValid())
        {
            T* pThis = (T*)*this;
            T* pThat = (T*)That;
            int n = (int)CMaaPtr < T >::MaxIndex();
            for (int i = 0; i < n; i++)
            {
                pThis[i] = pThat[i];
            }
        }
    }
    T& operator [] (int Index)
    {
        if (Index < 0 || Index + 1 < 0 || !CMaaPtr < T >::CheckExpand(Index + 1))
        {
            static T t;
            return t;
        }
        return CMaaPtr < T >::m_Ptr[Index];
    }
    const T& operator [] (int Index) const
    {
        int m = (int)CMaaPtr < T >::MaxIndex();
        if  (Index < 0 || Index >= m)
        {
            ////CMaaPtr_THROW;
            static T t;
            return t;
        }
        return CMaaPtr < T >::m_Ptr[Index];
    }
    void Swap(CMaaPtrAE<T>& That) noexcept
    {
        CMaaPtr<T>::Swap(That);
    }
};
//---------------------------------------------------------------------------
#else
//---------------------------------------------------------------------------
// TL_NEW version of CMaaPtr, CMaaPtrAE is slower
//---------------------------------------------------------------------------
template < class T > class CMaaPtr
{
protected:
    T    * m_Ptr;
    size_t m_MaxIndex, m_TotalItems, m_InitializedItems;
    int m_xThrow;

public:

    int GetThrowParameter() const noexcept
    {
        return m_xThrow;
    }
    void Swap ( CMaaPtr & That ) noexcept
    {
        CMaaSwap ( m_Ptr, That.m_Ptr );
        CMaaSwap ( m_MaxIndex, That.m_MaxIndex );
        CMaaSwap ( m_xThrow, That.m_xThrow );
        CMaaSwap ( m_TotalItems, That.m_TotalItems );
        CMaaSwap ( m_InitializedItems, That.m_InitializedItems);
    }
    // This constructor creates MaxIndex numbers of elements of class T.
    // Under Windows makes exeption if no free memory available.
    CMaaPtr ( CMaaPtr &x )
    :   m_Ptr ( nullptr ),
        m_MaxIndex ( 0 ),
        m_TotalItems(0),
        m_InitializedItems(0),
        m_xThrow(x.m_xThrow)
    {
        CMaaPtr<T> tmp(x.MaxIndex(), x.m_xThrow);
        if  (tmp.IsValid())
        {
            //memcpy(tmp, x, x.MaxIndex() * sizeof(T));
            int m = (int)x.m_InitializedItems;
            for (int i = 0; i < m; i++)
            {
                new_(tmp.m_Ptr + i, T(x[i]));
                tmp.m_InitializedItems = (i + 1);
            }
        }
        tmp.Swap(*this);
    }

    void DefInit(size_t m)
    {
        if  (m <= m_TotalItems)
        {
            while(m_InitializedItems < m)
            {
                new_(m_Ptr + m_InitializedItems++, T{});
            }
        }
    }

    void operator += (const CMaaPtr &x)
    {
        CMaaPtr<T> tmp(MaxIndex() + x.MaxIndex(), m_xThrow);
        if  (tmp.IsValid())
        {
            //          memcpy(tmp, *this, MaxIndex() * sizeof(T));
            int i;
            int m = (int)m_InitializedItems;
            for (i = 0; i < m; i++)
            {
                new_(tmp.m_Ptr + i, T((*this)[i]));
                tmp.m_InitializedItems = (i + 1);
            }
            m = (int)MaxIndex();
            DefInit(m);
            //          memcpy(MaxIndex + tmp, x, x.MaxIndex() * sizeof(T));
            int m2 = (int)x.m_InitializedItems;
            for (i = 0; i < m2; i++)
            {
                new_(tmp.m_Ptr + i + m, T(x.m_Ptr[i]));
                //tmp[i + (int)MaxIndex()] = x[i];
                tmp.m_InitializedItems = (i + m + 1);
            }
        }
        tmp.Swap(*this);
    }

    /*
    void operator += (T x)
    {
        CMaaPtr<T> tmp(MaxIndex + 1, m_xThrow);
        if (tmp.IsValid())
        {
            //memcpy(tmp, *this, MaxIndex() * sizeof(T));
            for (int i = 0; i < (int)MaxIndex(); i++)
            {
                tmp[i] = x[i];
            }
            tmp[MaxIndex] = x;
        }
        tmp.Swap(*this);
    }
    */

    void operator += (const T &x)
    {
        if  (m_TotalItems <= m_MaxIndex + 1)
        {
            DefInit(m_MaxIndex);
            if  (m_InitializedItems > m_MaxIndex)
            {
                (*this)[m_MaxIndex + 1] = x;
                m_MaxIndex++;
            }
            else
            {
                new_(m_Ptr + m_MaxIndex + 1, T(x));
                m_InitializedItems = m_MaxIndex + 1;
            }
        }
        else
        {
            CMaaPtr<T> tmp(m_MaxIndex + 1, m_xThrow, 2 * (m_MaxIndex + 1));
            if  (tmp.IsValid())
            {
                int i;
                int m = (int)m_InitializedItems;
                for (i = 0; i < m; i++)
                {
                    new_(tmp.m_Ptr + i, T((*this)[i]));
                    tmp.m_InitializedItems = (i + 1);
                }
                m = (int)MaxIndex();
                tmp.DefInit(m);
                new_(tmp.m_Ptr + m, T(x));
                tmp.m_InitializedItems = (m + 1);
            }
            tmp.Swap(*this);
        }
    }

    void operator += (T &x)
    {
        if  (m_TotalItems <= m_MaxIndex + 1)
        {
            DefInit(m_MaxIndex);
            if  (m_InitializedItems > m_MaxIndex)
            {
                (*this)[m_MaxIndex + 1] = x;
                m_MaxIndex++;
            }
            else
            {
                new_(m_Ptr + m_MaxIndex + 1, T(x));
                m_InitializedItems = m_MaxIndex + 1;
            }
        }
        else
        {
            CMaaPtr<T> tmp(m_MaxIndex + 1, m_xThrow, 2 * (m_MaxIndex + 1));
            if  (tmp.IsValid())
            {
                int i;
                int m = (int)m_InitializedItems;
                for (i = 0; i < m; i++)
                {
                    new_(tmp.m_Ptr + i, T((*this)[i]));
                    tmp.m_InitializedItems = (i + 1);
                }
                m = (int)MaxIndex();
                tmp.DefInit(m);
                new_(tmp.m_Ptr + m, T(x));
                tmp.m_InitializedItems = (m + 1);
            }
            tmp.Swap(*this);
        }
    }

    CMaaPtr<T> & operator = (const CMaaPtr<T> &That)
    {
        CMaaPtr<T> tmp(That.m_MaxIndex, m_xThrow, That.m_TotalItems);
        if  (tmp.IsValid())
        {
            int m = (int)That.m_InitializedItems;
            for (int i = 0; i < m; i++)
            {
                new_(tmp.m_Ptr + i, T(That[i]));
                tmp.m_InitializedItems = (i + 1);
            }
        }
        tmp.Swap(*this);
        return *this;
    }

    void append (T x)
    {
        (*this) += x;
    }

    CMaaPtr ( size_t MaxIndex = 0, int xThrow = 0, size_t TotalItems = 0)
    :   m_Ptr(nullptr),
        m_MaxIndex(MaxIndex),
        m_TotalItems(TotalItems > MaxIndex ? TotalItems : MaxIndex),
        m_InitializedItems(0),
        m_xThrow(xThrow)
    {
        if  ((size_t)sizeof(T) * m_TotalItems >= m_TotalItems)
        {
            m_Ptr = nullptr;
            try
            {
                m_Ptr = (T *)(TL_NEW char[(size_t)sizeof(T) * m_TotalItems]);
            }
            catch(...)
            {
            }
            if  (!m_Ptr && m_TotalItems)
            {
                INT3;
#ifndef __unix__
                OUT_DEBUG_STRING ( "MAARF:Memory allocation failed\r\n" );
#endif
                m_MaxIndex = m_TotalItems = 0;
                if  (xThrow > 0)
                {
                    CMaaPtr_THROW1;
                }
                if  (xThrow == 0)
                {
                    CMaaPtr_THROW;
                }
            }
        }
    }

    ~CMaaPtr () noexcept
    {
        size_t m = m_InitializedItems;
        while(m)
        {
            (m_Ptr + --m)->~T();
        }
        delete [] (char *)m_Ptr;
    }

    virtual bool IsValid () const noexcept
    {
        return m_Ptr != nullptr || m_TotalItems == 0;
    }

    operator T * () noexcept
    {
        if  (m_Ptr)
        {
            DefInit(m_MaxIndex); // for compatibility
        }
        return m_Ptr;
    }

    T & operator * () const noexcept
    {
        if  (m_Ptr)
        {
            DefInit(1); // for compatibility
        }
        return * m_Ptr;
    }

    T & operator [] ( int Index ) noexcept
    {
        if  (m_Ptr)
        {
            DefInit(Index + 1);
        }
        return m_Ptr [ Index ];
    }
    const T & operator [] ( int Index ) const noexcept
    {
        if  (m_Ptr)
        {
            DefInit(Index + 1);
        }
        return m_Ptr [ Index ];
    }
    T & at(int Index) noexcept
    {
        if  (m_Ptr)
        {
            DefInit(Index + 1);
        }
        return m_Ptr[Index];
    }
    const T&at(int Index) const noexcept
    {
        if  (m_Ptr)
        {
            DefInit(Index + 1);
        }
        return m_Ptr[Index];
    }
    size_t MaxIndex() const noexcept
    {
        return m_MaxIndex;
    }
    int count() const noexcept
    {
        return (int)m_MaxIndex;
    }
    int size() const noexcept
    {
        return (int)MaxIndex();
    }
    size_t Size() const noexcept
    {
        return m_MaxIndex * sizeof(T);
    }
    void Zero () noexcept
    {
        if  ( m_Ptr )
        {
            Memzero ( m_Ptr, ( size_t ) sizeof ( T ) * m_MaxIndex );
            if  (m_InitializedItems < m_MaxIndex)
            {
                m_InitializedItems = m_MaxIndex;
            }
        }
    }
    void fill(const T & value, int size = -1)
    {
        if  (m_Ptr && size <= (int)m_MaxIndex && size > 0)
        {
            int m = (int)m_InitializedItems;
            if  (m > size)
            {
                m = size;
            }
            int i;
            for (i = 0; i < m; i++)
            {
                m_Ptr[i] = value;
            }
            for (; i < size; i++)
            {
                new_(m_Ptr + i, T(value));
                m_InitializedItems = (i + 1);
            }
        }
    }
    virtual bool Resize ( int n )
    {
        if  (n <= (int)m_TotalItems)
        {
            if  (n >= (int)m_MaxIndex)
            {
                m_MaxIndex = n;
                DefInit(n);
            }
            else
            {
                int m = (int)m_InitializedItems;
                for (int i = m; i > n; )
                {
                    i--;
                    (m_Ptr + i)->~T();
                    m_MaxIndex = m_InitializedItems = i;
                }
            }
        }
        else
        {
            CMaaPtr < T > tmp(n);
            if  (!tmp.IsValid())
            {
                return false;
            }
            /*
            int nn = (int)m_MaxIndex < n ? (int)m_MaxIndex : n;
            for (int i = 0; i < nn; i++)
            {
                tmp[i] = (*this)[i];
            }
            */
            int nn = (int)m_InitializedItems < n ? (int)m_InitializedItems : n;
            for (int i = 0; i < nn; i++)
            {
                new_(tmp.m_Ptr + i, T((*this)[i]));
                tmp.m_InitializedItems = (i + 1);
            }
            //tmp.DefInit(n);
            Swap(tmp);
        }
        return true;
    }
    int Get_xThrow() const noexcept
    {
        return m_xThrow;
    }
    bool resize(int n)
    {
        CMaaPtr < T > tmp(n);
        if  (!tmp.IsValid())
        {
            return false;
        }
        /*
        int nn = (int)m_MaxIndex < n ? (int)m_MaxIndex : n;
        for (int i = 0; i < nn; i++)
        {
            tmp[i] = (*this)[i];
        }
        */
        //tmp.MaxIndex = nn;
        tmp.DefInit(n);
        Swap(tmp);
        return true;
    }
    static void Delete(T * ptr) noexcept
    {
        char* p = (char*)ptr;
        delete [] p;
    }
    T * Extract() noexcept
    {
        T * ptr = m_Ptr;
        m_Ptr = nullptr;
        return ptr;
    }
};
//---------------------------------------------------------------------------
// Automatic expandable CMaaPtr
template < class T > class CMaaPtrAE : public CMaaPtr < T >
{
public:
    CMaaPtrAE(size_t MaxIndex, int xThrow = 0)
    :   CMaaPtr < T > (MaxIndex, xThrow)
    {
    }
    CMaaPtrAE(CMaaPtrAE<T> & That)
    :   CMaaPtr < T > (That.m_MaxIndex, That.m_xThrow, That.m_TotalItems)
    {
        if  (CMaaPtr < T >::IsValid() && That.IsValid())
        {
            T * pThis = (T *)*this;
            T * pThat = (T *)That;
            int n = (int) CMaaPtr < T >::m_InitializedItems;
            for (int i = 0; i < n; i++)
            {
                new_(pThis + i, T(pThat[i]));
            }
        }
    }
    T & operator [] (int Index)
    {
        int m = (int) CMaaPtr < T >::m_TotalItems;
        if  (Index >= m )
        {
            int N = 2 * m > Index ? 2 * m : Index + 1;
            CMaaPtrAE < T > Expand(N, CMaaPtr < T >::m_xThrow);
            if  (!Expand.IsValid())
            {
                //CMaaPtr_THROW;
                static T t{};
                return t;
            }
            m = (int)CMaaPtr < T >::m_InitializedItems;
            for (int i = 0; i < m; i++)
            {
                new_(Expand.m_Ptr + i, T(CMaaPtr < T >::m_Ptr[i]));
                Expand.m_InitializedItems = (i + 1);
            }
            //memcpy((T*)Expand, (T*)*this, CMaaPtr < T >::Size());
            Swap(Expand);
        }
        return CMaaPtr < T >::operator [] (Index);
    }
    void Swap(CMaaPtrAE<T> & That) noexcept
    {
        CMaaPtr<T>::Swap(That);
    }
};
//---------------------------------------------------------------------------
#endif

//---------------------------------------------------------------------------
#ifndef TOOLSLIB_SINGLE_THREAD
void CMaaAllocatorBasicLock() noexcept;
void CMaaAllocatorBasicUnLock() noexcept;
#endif
//---------------------------------------------------------------------------
template<class T> void CMaaAllocatorLock(T *) noexcept
{
#ifndef TOOLSLIB_SINGLE_THREAD
    CMaaAllocatorBasicLock();
#endif
}
template<class T> void CMaaAllocatorUnLock(T *) noexcept
{
#ifndef TOOLSLIB_SINGLE_THREAD
    CMaaAllocatorBasicUnLock();
#endif
}
// to redefine:
// template<> void CMaaAllocatorLock(MyClass *);
// template<> void CMaaAllocatorUnLock(MyClass *);
//typedef void (*lf(T *)) __lf;
#define TL_NO_CMaaAllocatorStaticLocker
#ifndef TL_NO_CMaaAllocatorStaticLocker
template <class T> class CMaaAllocatorStaticLocker
{
public:
    static void CreateFn(T* obj) noexcept
    {
#ifndef TOOLSLIB_SINGLE_THREAD
        __GLock__LockFn(obj, true);
#endif
    }
    static void InitLockFn(T* obj) noexcept
    {
#ifndef TOOLSLIB_SINGLE_THREAD
        __GLock__LockFn(obj, true)->Lock();
#endif
    }
    static void LockFn(T * obj) noexcept
    {
#ifndef TOOLSLIB_SINGLE_THREAD
        // CMaaAllocatorLock<T>(obj); // version before 19.10.2021+
        __GLock__LockFn(obj)->Lock();
#endif
    }
    static void UnLockFn(T * obj) noexcept
    {
#ifndef TOOLSLIB_SINGLE_THREAD
        //CMaaAllocatorUnLock<T>(obj); // version before 19.10.2021+
        __GLock__LockFn(obj)->UnLock();
#endif
    }
};
#endif
//---------------------------------------------------------------------------
template<class T
#ifndef TOOLSLIB_SINGLE_THREAD
#ifndef TL_NO_CMaaAllocatorStaticLocker
#ifdef _WIN32
    //, typename Fn
    , class CLocker = CMaaAllocatorStaticLocker<T>
#else
    , class CLocker = CMaaAllocatorStaticLocker<T>
#endif
#endif
#endif
> class CMaaFixedAllocator
{
    char * pMem[sizeof(size_t) * 8];
    void * m_pSList;
    size_t m_Ref;
    size_t m_TotalCount, m_FreeCount;
    int m_AllocatorType; // 0 - unknown, -1 - w/o of internal syncronization (NewUl/DeleteUl/AddRefUl/DelRefUl), 1 - synchronized allocations (New/Delete/AddRef/DelRef)

protected:
//#ifndef TOOLSLIB_SINGLE_THREAD // noops are good optimized, #ifndef not very required
    class Locker
    {
    public:
        Locker() noexcept
        {
#ifndef TOOLSLIB_SINGLE_THREAD
#ifdef TL_NO_CMaaAllocatorStaticLocker
            __GLock__LockFn(T_NULL(T*))->Lock();
#else
            CLocker::LockFn(T_NULL(T*));
#endif
#endif
        }
        Locker(bool b) noexcept
        {
#ifndef TOOLSLIB_SINGLE_THREAD
#ifdef TL_NO_CMaaAllocatorStaticLocker
            __GLock__LockFn(T_NULL(T*), b)->Lock();
#else
            CLocker::LockFn(T_NULL(T*));
#endif
#endif
        }
        ~Locker() noexcept
        {
#ifndef TOOLSLIB_SINGLE_THREAD
#ifdef TL_NO_CMaaAllocatorStaticLocker
            __GLock__LockFn(T_NULL(T*))->UnLock();
#else
            CLocker::UnLockFn(T_NULL(T*));
#endif
#endif
        }
        static void CreateMtx() noexcept
        {
#ifndef TOOLSLIB_SINGLE_THREAD
#ifdef TL_NO_CMaaAllocatorStaticLocker
            __GLock__LockFn(T_NULL(T*), true);
#else
            CLocker::CreateFn(T_NULL(T*));
            //CMaaAllocatorStaticLocker<T>::CreateFn(T_NULL(T*));
#endif
#endif
        }
    };
//#endif
public:
    CMaaFixedAllocator(int AllocatorType = 0) noexcept
    {
#ifdef NEW_DELETE_PRINTF
        printf("CMaaFixedAllocator::CMaaFixedAllocator() this=%p\n", this); // !NEW
#endif
        memset(pMem, 0, sizeof(pMem));
        m_pSList = nullptr;
        m_Ref = 0;
        m_TotalCount = m_FreeCount = 0;
        m_AllocatorType = AllocatorType;
        if  (AllocatorType >= 0)
        {
//#ifndef TOOLSLIB_SINGLE_THREAD
            Locker::CreateMtx();
//#endif
        }
    }
    ~CMaaFixedAllocator() noexcept
    {
        for (int i = (int)(sizeof(size_t) * 8); i--; )
        {
#ifdef NEW_DELETE_PRINTF
            if  (pMem[i])
            {
                printf("~CMaaFixedAllocator() delete %p\n", pMem[i]); // !NEW
            }
#endif
            delete [] pMem[i];     pMem[i] = nullptr;
        }
    }
    int GetAllocatorType() const noexcept
    {
        return m_AllocatorType;
    }
    bool PreAllocate(size_t CountTotal, size_t FreeCountRequired = 0, size_t CountAdd = 0)
    {
        const size_t cnt1 = m_TotalCount;
        while(m_TotalCount < CountTotal || m_FreeCount < FreeCountRequired || m_TotalCount - cnt1 < CountAdd)
        {
            if  (Alloc() < 0)
            {
                return false;
            }
        }
        return true;
    }
    size_t ItemSize() const noexcept
    {
#ifdef __ALLOCATOR_RESERVE_PTR
        return sizeof(T) + sizeof(void *);
#else
        return sizeof(T) > sizeof(void *) ? sizeof(T) : sizeof(void *);
#endif
    }
protected:
    int Alloc()
    {
        for (int i = 0; i < (int)(sizeof(size_t) * 8); i++)
        {
            if  (!pMem[i])
            {
                const size_t n = ((size_t)1) << i;
                size_t sz = ItemSize();
                //try
                //{
                    pMem[i] = n < SIZE_MAX / sz ? TL_NEW char[n * sz] : nullptr;
#ifdef NEW_DELETE_PRINTF
                    printf("CMaaFixedAllocator::Alloc() TL_NEW %p %d*%d=%d\n", pMem[i], n, (int)sz, (int)(n * sz)); // !NEW
#endif
#ifdef __ALLOCATOR_FILL
                    if  (pMem[i])
                    {
                        memset(pMem[i], __ALLOCATOR_FILL_INIT_CHAR, n * sz);
                    }
#endif
                //}
                //catch(...)
                //{
                    //throw;
                //}
                if  (pMem[i])
                {
                    char * m = pMem[i];
                    for (size_t j = 1; j < n; j++)
                    {
                        *(void **)m = m + sz;
                        m += sz;
                    }
                    *(void **)m = m_pSList;
                    m_pSList = pMem[i];
                    m_TotalCount += n;
                    m_FreeCount += n;
                }
                return i;
            }
        }
        return -1;
    }
public:
    T * New2(CMaaFixedAllocator<T> ** pVar)
    {
        void * p = m_pSList;
        if  (!p)
        {
            Alloc();
            p = m_pSList;
        }
        if  (p)
        {
            ++m_Ref;
            --m_FreeCount;
            m_pSList = *(void **)p;
        }
        else if (!m_Ref)
        {
            *pVar = nullptr;
#ifdef NEW_DELETE_PRINTF
            printf("CMaaFixedAllocator::New2 delete this=%p\n", this); // !NEW
#endif
            delete this;
        }
#ifdef __ALLOCATOR_RESERVE_PTR
        if  (p)
        {
            memset(p, __ALLOCATOR_FILL_ALLOC_CHAR, sizeof(void *) + sizeof(T));
            p = sizeof(void *) + (char *)p;
        }
#else
#ifdef __ALLOCATOR_FILL
        if  (p)
        {
            memset(p, __ALLOCATOR_FILL_ALLOC_CHAR, sizeof(T));
        }
#endif
#endif
#ifdef NEW_DELETE_PRINTF
        printf("CMaaFixedAllocator::New2() %p\n", p); // !NEW
#endif
        return (T *)p;
    }
    void Delete2(T * ptr, CMaaFixedAllocator<T> ** pVar) noexcept
    {
        if  (ptr)
        {
#ifdef NEW_DELETE_PRINTF
            printf("CMaaFixedAllocator::Delete2() %p\n", ptr); // !NEW
#endif
#ifdef __ALLOCATOR_RESERVE_PTR
            ptr = (T *)((char *)ptr - sizeof(void *));
            memset(ptr, __ALLOCATOR_FILL_FREE_CHAR, sizeof(T) + sizeof(void *));
#else
#ifdef __ALLOCATOR_FILL
            memset(ptr, __ALLOCATOR_FILL_FREE_CHAR, sizeof(T));
#endif
#endif
            *(void **)ptr = m_pSList;
            m_pSList = ptr;
            ++m_FreeCount;
            if  (--m_Ref == 0)
            {
                *pVar = nullptr;
#ifdef NEW_DELETE_PRINTF
                printf("CMaaFixedAllocator::Delete2 delete this=%p\n", this); // !NEW
#endif
                delete this;
            }
        }
    }
    static T * New(CMaaFixedAllocator<T> ** pVar)
    {
//#ifndef TOOLSLIB_SINGLE_THREAD
        Locker lk(!*pVar);
//#endif

        //T * p = nullptr;
        CMaaFixedAllocator<T>* a = *pVar;
#ifndef TOOLSLIB_SINGLE_THREAD
        //try
#endif
        //{
            if  (!a)
            {
                *pVar = a = TL_NEW CMaaFixedAllocator<T>;
            }
            T * p = a ? a->New2(pVar) : nullptr;
        //}
#ifndef TOOLSLIB_SINGLE_THREAD
        //catch(...)
        //{
            //if (a && !a->m_Ref)
            //{
            //    *pVar = nullptr;
            //    delete a;
            //}
            //throw;
        //}
#endif
        return p;
    }
    static void Delete(T * ptr, CMaaFixedAllocator<T> ** pVar) noexcept
    {
        if  (ptr)
        {
//#ifndef TOOLSLIB_SINGLE_THREAD
            Locker lk;
//#endif
            CMaaFixedAllocator<T> * a = *pVar;
            if  (a)
            {
                a->Delete2(ptr, pVar);
            }
        }
    }
    static T * NewUl(CMaaFixedAllocator<T> ** pVar)
    {
        //T * p = nullptr;
        CMaaFixedAllocator<T>* a = *pVar;
        //try
        //{
            if  (!a)
            {
                *pVar = a = TL_NEW CMaaFixedAllocator<T>;
            }
            T * p = a ? a->New2(pVar) : nullptr;
        //}
        //catch(...)
        //{
        //    if (a && !a->m_Ref)
        //    {
        //        *pVar = nullptr;
        //        delete a;
        //    }
        //    throw;
        //}
        return p;
    }
    static void DeleteUl(T * ptr, CMaaFixedAllocator<T> ** pVar) noexcept
    {
        if  (ptr)
        {
            CMaaFixedAllocator<T> * a = *pVar;
            if  (a)
            {
                a->Delete2(ptr, pVar);
            }
        }
    }
    size_t AddRef() noexcept
    {
//#ifndef TOOLSLIB_SINGLE_THREAD
        Locker lk;
//#endif
        return ++m_Ref;
    }
    size_t DelRef(CMaaFixedAllocator<T> ** pVar = nullptr) noexcept
    {
        size_t Ref;
        {
//#ifndef TOOLSLIB_SINGLE_THREAD
            Locker lk;
//#endif
            Ref = --m_Ref;
            if (!Ref && pVar)
            {
                *pVar = nullptr;
            }
        }
        if (!Ref)
        {
            delete this;
        }
        return Ref;
    }
    size_t AddRefUl() noexcept
    {
        return ++m_Ref;
    }
    size_t DelRefUl(CMaaFixedAllocator<T> ** pVar = nullptr) noexcept
    {
        const size_t Ref = --m_Ref;
        if  (!Ref && pVar)
        {
            *pVar = nullptr;
        }
        if  (!Ref)
        {
            delete this;
        }
        return Ref;
    }
    static bool CreateAddRef(CMaaFixedAllocator<T>** pVar)
    {
//#ifndef TOOLSLIB_SINGLE_THREAD
        Locker lk(!*pVar);
//#endif

        bool b = false;
#ifndef TOOLSLIB_SINGLE_THREAD
        //try
#endif
        //{
            CMaaFixedAllocator<T>* a = *pVar;
            if (!a)
            {
                *pVar = a = TL_NEW CMaaFixedAllocator<T>;
                b = a && a->AddRefUl(); // stay-in-memory
            }
            else
            {
                a->AddRefUl(); // 2023+
                b = true;
            }
        //}
#ifndef TOOLSLIB_SINGLE_THREAD
        //catch (...)
        //{
        //    throw;
        //}
#endif
        return b;
    }
    static bool CreateAddRefUl(CMaaFixedAllocator<T>** pVar)
    {
        bool b = false;
        //try
        //{
            CMaaFixedAllocator<T>* a = *pVar;
            if (!a)
            {
                *pVar = a = TL_NEW CMaaFixedAllocator<T>;
                b = a && a->AddRefUl(); // stay-in-memory
            }
            else
            {
                a->AddRefUl(); // 2023+
                b = true;
            }
        //}
        //catch (...)
        //{
        //    throw;
        //}
        return b;
    }

    //int m_AllocatorType; // 0 - unknown, -1 - w/o of internal syncronization (NewUl/DeleteUl/AddRefUl/DelRefUl/CreateAddRefUl), 1 - synchronized allocations (New/Delete/AddRef/DelRef/CreateAddRef)
    static T * NewEx_static(CMaaFixedAllocator<T> ** pVar, int default_allocation_type = 1)
    {
        int all_type = pVar && *pVar ? (*pVar)->GetAllocatorType() : 0;
        all_type = all_type != 0 ? all_type : default_allocation_type;
        return all_type < 0 ? NewUl(pVar) : New(pVar);
    }

    static void DeleteEx_static(T * ptr, CMaaFixedAllocator<T> ** pVar, int default_allocation_type = 1) noexcept
    {
        int all_type = pVar && *pVar ? (*pVar)->GetAllocatorType() : 0;
        all_type = all_type != 0 ? all_type : default_allocation_type;
        if  (all_type < 0)
        {
            DeleteUl(ptr, pVar);
        }
        else
        {
            Delete(ptr, pVar);
        }
    }

    T * NewEx(CMaaFixedAllocator<T> ** pVar, int default_allocation_type = 1)
    {
        int all_type = GetAllocatorType();
        all_type = all_type != 0 ? all_type : default_allocation_type;
        return all_type < 0 ? NewUl(pVar) : New(pVar);
    }

    void DeleteEx(T * ptr, CMaaFixedAllocator<T> ** pVar, int default_allocation_type = 1) noexcept
    {
        int all_type = GetAllocatorType();
        all_type = all_type != 0 ? all_type : default_allocation_type;
        if  (all_type < 0)
        {
            DeleteUl(ptr, pVar);
        }
        else
        {
            Delete(ptr, pVar);
        }
    }

    size_t AddRefEx(int default_allocation_type = 1) noexcept
    {
        int all_type = GetAllocatorType();
        all_type = all_type != 0 ? all_type : default_allocation_type;
        return all_type < 0 ? AddRefUl() : AddRef();
    }

    size_t DelRefEx(CMaaFixedAllocator<T> ** pVar = nullptr, int default_allocation_type = 1) noexcept
    {
        int all_type = GetAllocatorType();
        all_type = all_type != 0 ? all_type : default_allocation_type;
        return all_type < 0 ? DelRefUl(pVar) : DelRef(pVar);
    }
};
//---------------------------------------------------------------------------
template<class T> class CMaaFixedAllocatorCreator
{
    CMaaFixedAllocator<T>** m_ptr;
    CMaaFixedAllocatorCreator() = delete;
public:
    CMaaFixedAllocatorCreator(CMaaFixedAllocator<T>** ptr)
    {
        CMaaFixedAllocator<T>::CreateAddRef(m_ptr = ptr);
    }
    ~CMaaFixedAllocatorCreator()
    {
        (*m_ptr)->DelRef(m_ptr);
    }
};
//---------------------------------------------------------------------------
template<class T> class CMaaFixedAllocatorCreatorUl
{
    CMaaFixedAllocator<T>** m_ptr;
    CMaaFixedAllocatorCreatorUl() = delete;
public:
    CMaaFixedAllocatorCreatorUl(CMaaFixedAllocator<T>** ptr)
    {
        CMaaFixedAllocator<T>::CreateAddRefUl(m_ptr = ptr);
    }
    ~CMaaFixedAllocatorCreatorUl()
    {
        (*m_ptr)->DelRefUl(m_ptr);
    }
};
//---------------------------------------------------------------------------

#ifdef __unix__
#define __cdecl
#endif

#if 0
#define ADD_ALLOCATOR(T) \
static CMaaFixedAllocator<T> * s_pAllocator; \
static CMaaFixedAllocatorCreator<T> s_AllocatorCreator; \
public: \
void *__cdecl operator new__(size_t count) \
{ \
    return CMaaFixedAllocator<T>::New(&s_pAllocator); \
} \
void* __cdecl operator new__(size_t /*count*/, const char * /*lpszFileName*/, int /*nLine*/, sDbgTmp *) \
{ \
    return CMaaFixedAllocator<T>::New(&s_pAllocator); \
} \
void __cdecl operator delete(void * object) \
{ \
    CMaaFixedAllocator<T>::Delete((T *)object, &s_pAllocator); \
} \
void __cdecl operator delete(void* object, const char * /* lpszFileName */, int /* nLine */, sDbgTmp*) \
{ \
    CMaaFixedAllocator<T>::Delete((T *)object, &s_pAllocator); \
}

#define ADD_UL_ALLOCATOR(T) \
static CMaaFixedAllocator<T> * s_pAllocator; \
static CMaaFixedAllocatorCreator<T> s_AllocatorCreatorUl; \
public: \
void *__cdecl operator new__(size_t /*count*/) \
{ \
    return CMaaFixedAllocator<T>::NewUl(&s_pAllocator); \
} \
void* __cdecl operator new__(size_t /*count*/, const char * /*lpszFileName*/, int /*nLine*/, sDbgTmp *) \
{ \
    return CMaaFixedAllocator<T>::NewUl(&s_pAllocator); \
} \
void __cdecl operator delete(void * object) \
{ \
    CMaaFixedAllocator<T>::DeleteUl((T *)object, &s_pAllocator); \
} \
void __cdecl operator delete(void* object, const char * /* lpszFileName */, int /* nLine */, sDbgTmp*) \
{ \
    CMaaFixedAllocator<T>::DeleteUl((T *)object, &s_pAllocator); \
}

#define ADD_SPECIFIC_ALLOCATOR(T) \
static CMaaFixedAllocator<T> * s_pAllocator; \
public: \
void *__cdecl operator new__(size_t count) \
{ \
    return CMaaFixedAllocator<T>::NewEx_static(&s_pAllocator); \
} \
void* __cdecl operator new__(size_t /*count*/, const char * /*lpszFileName*/, int /*nLine*/, sDbgTmp *) \
{ \
    return CMaaFixedAllocator<T>::NewEx_static(&s_pAllocator); \
} \
void __cdecl operator delete(void * object) \
{ \
    CMaaFixedAllocator<T>::DeleteEx_static((T *)object, &s_pAllocator); \
} \
void __cdecl operator delete(void* object, const char * /* lpszFileName */, int /* nLine */, sDbgTmp*) \
{ \
    CMaaFixedAllocator<T>::DeleteEx_static((T *)object, &s_pAllocator); \
}

#else

#ifdef _WIN32
#define ADD_ALLOCATOR(T) static CMaaFixedAllocator<T> * s_pAllocator; static CMaaFixedAllocatorCreator<T> s_AllocatorCreator; public: void *__cdecl operator new__(size_t /*count*/) { return CMaaFixedAllocator<T>::New(&s_pAllocator); } void* __cdecl operator new__(size_t, const char *, int, sDbgTmp*) { return CMaaFixedAllocator<T>::New(&s_pAllocator); } void __cdecl operator delete(void * object) { CMaaFixedAllocator<T>::Delete(static_cast<T *>(object), &s_pAllocator); } void __cdecl operator delete(void* object, const char *, int, sDbgTmp*) { CMaaFixedAllocator<T>::Delete(static_cast<T *>(object), &s_pAllocator); }
#define ADD_UL_ALLOCATOR(T) static CMaaFixedAllocator<T> * s_pAllocator; static CMaaFixedAllocatorCreatorUl<T> s_AllocatorCreator; public: void *__cdecl operator new__(size_t /*count*/) { return CMaaFixedAllocator<T>::NewUl(&s_pAllocator); } void* __cdecl operator new__(size_t, const char *, int, sDbgTmp *) { return CMaaFixedAllocator<T>::NewUl(&s_pAllocator); } void __cdecl operator delete(void * object) { CMaaFixedAllocator<T>::DeleteUl(static_cast<T*>(object), &s_pAllocator); } void __cdecl operator delete(void* object, const char *, int, sDbgTmp*) { CMaaFixedAllocator<T>::DeleteUl(static_cast<T*>(object), &s_pAllocator); }
#define ADD_SPECIFIC_ALLOCATOR(T) static CMaaFixedAllocator<T> * s_pAllocator; public: void *__cdecl operator new__(size_t count) { return CMaaFixedAllocator<T>::NewEx_static(&s_pAllocator); } void* __cdecl operator new__(size_t, const char *, int, sDbgTmp*) { return CMaaFixedAllocator<T>::NewEx_static(&s_pAllocator); } void __cdecl operator delete(void * object) { CMaaFixedAllocator<T>::DeleteEx_static(static_cast<T*>(object), &s_pAllocator); } void __cdecl operator delete(void* object, const char *, int, sDbgTmp*) { CMaaFixedAllocator<T>::DeleteEx_static(static_cast<T*>(object), &s_pAllocator); }
#else
#define ADD_ALLOCATOR(T) static CMaaFixedAllocator<T> * s_pAllocator; static CMaaFixedAllocatorCreator<T> s_AllocatorCreator; public: void *__cdecl operator new__(size_t /*count*/) { return CMaaFixedAllocator<T>::New(&s_pAllocator); } void __cdecl operator delete(void * object) { CMaaFixedAllocator<T>::Delete(static_cast<T *>(object), &s_pAllocator); }
#define ADD_UL_ALLOCATOR(T) static CMaaFixedAllocator<T> * s_pAllocator; static CMaaFixedAllocatorCreatorUl<T> s_AllocatorCreator; public: void *__cdecl operator new__(size_t /*count*/) { return CMaaFixedAllocator<T>::NewUl(&s_pAllocator); } void __cdecl operator delete(void * object) { CMaaFixedAllocator<T>::DeleteUl(static_cast<T*>(object), &s_pAllocator); }
#define ADD_SPECIFIC_ALLOCATOR(T) static CMaaFixedAllocator<T> * s_pAllocator; public: void *__cdecl operator new__(size_t count) { return CMaaFixedAllocator<T>::NewEx_static(&s_pAllocator); } void __cdecl operator delete(void * object) { CMaaFixedAllocator<T>::DeleteEx_static(static_cast<T*>(object), &s_pAllocator); }
#endif

#endif

#define    DEF_ALLOCATOR(T) CMaaFixedAllocator< T >* T::s_pAllocator = nullptr;   CMaaFixedAllocatorCreator< T > T::s_AllocatorCreator(&T::s_pAllocator);
#define DEF_UL_ALLOCATOR(T) CMaaFixedAllocator< T >* T::s_pAllocator = nullptr; CMaaFixedAllocatorCreatorUl< T > T::s_AllocatorCreator(&T::s_pAllocator);

#define    DEF_ALLOCATOR_(T) template<> CMaaFixedAllocator< T >* T::s_pAllocator = nullptr; template<>   CMaaFixedAllocatorCreator< T > T::s_AllocatorCreator(&T::s_pAllocator);
#define DEF_UL_ALLOCATOR_(T) template<> CMaaFixedAllocator< T >* T::s_pAllocator = nullptr; template<> CMaaFixedAllocatorCreatorUl< T > T::s_AllocatorCreator(&T::s_pAllocator);

/*
class X
{
     void *__cdecl operator TL_NEW(size_t count);
     //void *__cdecl operator TL_NEW(size_t count, void * object) throw();
     //void *__cdecl operator TL_NEW(size_t count, const std::nothrow_t&) throw();
     void __cdecl operator delete(void * object);
     //void __cdecl operator delete(void * object, void * memory) throw();
     //void __cdecl operator delete(void * object, const std::nothrow_t&) throw();

     //void *operator TL_NEW[](std::size_t _Count) throw(std::bad_alloc);
     //void *operator TL_NEW[](std::size_t _Count, const std::nothrow_t&) throw();
     //void *operator TL_NEW[](std::size_t _Count, void* _Ptr) throw();
     //void operator delete[](void* _Ptr) throw();
     //void operator delete[](void *, void *) throw();
     //void operator delete[](void* _Ptr, const std::nothrow_t&) throw();

     static CMaaFixedAllocator<X> * s_pAllocator;
};
X::CMaaFixedAllocator<X> * s_pAllocator = nullptr;
*/

//---------------------------------------------------------------------------
inline _dword CMaaStandardHashFunction(const unsigned char* p, int len) noexcept
{
    _dword x = 0;
#ifdef TRY_HF_OPT
    for (int i = len >> _dword_shift; i--; )
    {
        x = ((x << 7) | (x >> 25)) ^ *(_dword *)p;
        p += sizeof(_dword);
    }
    for (int i = (len & _dword_mask); i--; )
    {
        x = ((x << 7) | (x >> 25)) ^ *p++;
    }
#else
    for (int i = len; i--; )
    {
        x = ((x << 7) | (x >> 25)) ^ *p++;
    }
#endif
    return x;
}
//---------------------------------------------------------------------------
inline _uqword CMaaStandardHashFunction64(const unsigned char* p, int len) noexcept
{
    _uqword x = 0;
    if  ((size_t)len <= sizeof(_uqword))
    {
        memcpy(&x, p, len);
        return x;
    }
#ifdef TRY_HF_OPT
    for (int i = len >> _qword_shift; i--; )
    {
        x = ((x << 7) | (x >> 57)) ^ *(_uqword *)p;
        p += sizeof(_uqword);
    }
    for (int i = (len & _qword_mask); i--; )
    {
        x = ((x << 7) | (x >> 57)) ^ *p++;
    }
#else
    for (int i = len; i--; )
    {
        x = ((x << 7) | (x >> 57)) ^ *p++;
    }
#endif
    return x;
}
/*
#ifdef _WIN64
extern "C"
{
    _dword CMaaStandardHashFunction32_win(const void* p, _dword len) noexcept;
    _uqword CMaaStandardHashFunction64_win(const void* p, _dword len) noexcept;
}
//#define CMaaStandardHashFunction CMaaStandardHashFunction32_win // +2.1% speed if len=1000, -10% if len=8
//#define CMaaStandardHashFunction64 CMaaStandardHashFunction64_win // -12.5% speed
#endif
*/
//---------------------------------------------------------------------------
template <class Key> _dword CMaaHashFunction(const Key& k) noexcept
{
    if constexpr (sizeof(Key) == sizeof(_dword))
    {
        return *(_dword*)&k;
    }
#ifdef TRY_HF8_OPT
    else if constexpr (sizeof(Key) == 2 * sizeof(_dword))
    {
        //_dword x = *(_dword*)&k;
        //return ((x << 7) | (x >> 25)) ^ *(1 + (_dword *)&k);
        return *((_dword*)&k) ^ *(1 + (_dword*)&k);
        //return *(1 + (_dword *)&k) ^ *(_dword *)&k;
    }
#endif
    else
    {
        return CMaaStandardHashFunction((const unsigned char*)&k, (int)sizeof(Key));
    }
}
//---------------------------------------------------------------------------
template <class Key> _dword CMaaHashFunction2(const Key k) noexcept
{
    if constexpr (sizeof(Key) == sizeof(_dword))
    {
        return (_dword)k;
    }
#ifdef TRY_HF8_OPT
    else if constexpr (sizeof(Key) == 2 * sizeof(_dword))
    {
        return ((_dword*)k) ^ (_dword*)(k >> 32);
    }
#endif
    else
    {
        return CMaaStandardHashFunction((const unsigned char*)&k, (int)sizeof(Key));
    }
}
//---------------------------------------------------------------------------
//template <> _dword CMaaHashFunction<CMaaString>(const CMaaString & k) noexcept;
//template <> _dword CMaaHashFunction<CMaaString>(const CMaaString & k) noexcept
//{
//     ...
//}
template <> _dword CMaaHashFunction<int>(const int &k) noexcept;
//#ifndef __unix__
template <> _dword CMaaHashFunction<_dword>(const _dword &k) noexcept;
//#endif
template <> _dword CMaaHashFunction<unsigned>(const unsigned &k) noexcept;
//inline _dword CMaaHashFunction(const int &k) noexcept { return k; }
////inline _dword CMaaHashFunction(const _dword &k) noexcept { return k; }
//inline _dword CMaaHashFunction(const unsigned &k) noexcept { return k; }
class CMaaString;
template <> _dword CMaaHashFunction<CMaaString>(const CMaaString & k) noexcept;
inline _dword CMaaHashFunction(const CMaaString & k) noexcept;
//---------------------------------------------------------------------------
inline _dword CMaaHashFunction(const int &k) noexcept
{
    return (_dword)k;
}
#ifndef __unix__
inline _dword CMaaHashFunction(const _dword &k) noexcept
{
    return (_dword)k;
}
#endif
inline _dword CMaaHashFunction(const unsigned &k) noexcept
{
    return (_dword)k;
}
inline _dword CMaaHashFunction(const _qword &k) noexcept
{
    return ((_dword)k) ^ (_dword)(k >> 32);
}
inline _dword CMaaHashFunction(const _uqword &k) noexcept
{
    return ((_dword)k) ^ (_dword)(k >> 32);
}
//---------------------------------------------------------------------------
inline _dword CMaaHashFunction2(int k) noexcept
{
    return (_dword)k;
}
#ifndef __unix__
inline _dword CMaaHashFunction2(_dword k) noexcept
{
    return (_dword)k;
}
#endif
inline _dword CMaaHashFunction2(unsigned k) noexcept
{
    return (_dword)k;
}
inline _dword CMaaHashFunction2(_word k) noexcept
{
    return (_dword)k;
}
inline _dword CMaaHashFunction2(_qword k) noexcept
{
    return ((_dword)k) ^ (_dword)(k >> 32);
}
inline _dword CMaaHashFunction2(_uqword k) noexcept
{
    return ((_dword)k) ^ (_dword)(k >> 32);
}
template <> _dword CMaaHashFunction2<int>(const int k) noexcept;
//#ifndef __unix__
template <> _dword CMaaHashFunction2<_dword>(const _dword k) noexcept;
//#endif
template <> _dword CMaaHashFunction2<unsigned>(const unsigned k) noexcept;
template <> _dword CMaaHashFunction2<_word>(const _word k) noexcept;
template <> _dword CMaaHashFunction2<_qword>(const _qword k) noexcept;
template <> _dword CMaaHashFunction2<_uqword>(const _uqword k) noexcept;
//---------------------------------------------------------------------------
#define CMaaUnivHash_IsNew
#ifdef CMaaUnivHash_IsNew
#define CMaaUnivHash CMaaUnivHash_New
#define CMaaUnivHash_KeyIsClass CMaaUnivHash_New_KeyIsClass
#define CMaaUnivHash_ClassPtr CMaaUnivHash_NewClassPtr
#else
#define CMaaUnivHash CMaaUnivHash_Fast
#define CMaaUnivHash_KeyIsClass CMaaUnivHash_Fast_KeyIsClass
#define CMaaUnivHash_ClassPtr CMaaUnivHash_FastClassPtr
#endif
#define CMaaUnivHash2 CMaaUnivHash_New2
//---------------------------------------------------------------------------
//extern int gggg___aa;
//---------------------------------------------------------------------------

//for shared allocator use static allocator object definition like:
//#ifdef TOOLSLIB_SHARED_ALLOCATOR
//template<> CMaaFixedAllocator<CMaaUnivHash_New<CMaaString, char>::Record >* CMaaUnivHash_New<CMaaString, char>::Record::s_pAllocator = nullptr;
//template<> CMaaFixedAllocatorCreator<CMaaUnivHash_New<CMaaString, char>::Record > CMaaUnivHash_New<CMaaString, char>::Record::s_AllocatorCreator(&CMaaUnivHash_New<CMaaString, char>::Record::s_pAllocator);
//or
//DEF_ALLOCATOR_CMaaUnivHash(CMaaString, char);
//#endif

template < class Key, class Data, bool bStandartHash = true > class CMaaUnivHash_New
{
//public:
//protected:
    struct Record
    {
        Record * pNext;
        Key  K;
        Data D;
        Record(const Key &k, const Data &d) noexcept( noexcept(Key(K)) && noexcept(Data(d)) )
        :   K(k),
            D(d)
        {
        }
#ifdef TOOLSLIB_SHARED_ALLOCATOR
        //ADD_UL_ALLOCATOR(Record)
        ADD_ALLOCATOR(Record)
#define DEF3_ALLOCATOR_CMaaUnivHash(A,B,F) template<> CMaaFixedAllocator< CMaaUnivHash_New< A, B, F >::Record >* CMaaUnivHash_New< A, B, F >::Record::s_pAllocator = nullptr; template<>   CMaaFixedAllocatorCreator< CMaaUnivHash_New< A, B, F >::Record > CMaaUnivHash_New< A, B, F >::Record::s_AllocatorCreator(&CMaaUnivHash_New< A, B, F >::Record::s_pAllocator);
//#define DEF3_ALLOCATOR_CMaaUnivHash(A,B,F) template<> CMaaFixedAllocator< CMaaUnivHash_New< A, B, F >::Record >* CMaaUnivHash_New< A, B, F >::Record::s_pAllocator = nullptr; template<> CMaaFixedAllocatorCreatorUl< CMaaUnivHash_New< A, B, F >::Record > CMaaUnivHash_New< A, B, F >::Record::s_AllocatorCreator(&CMaaUnivHash_New< A, B, F >::Record::s_pAllocator);
#define DEF_ALLOCATOR_CMaaUnivHash(A,B) DEF3_ALLOCATOR_CMaaUnivHash(A,B,true)
#else
#define DEF3_ALLOCATOR_CMaaUnivHash(A,B,F)
#define DEF_ALLOCATOR_CMaaUnivHash(A,B)
#endif
    };

#ifndef TOOLSLIB_SHARED_ALLOCATOR
    CMaaFixedAllocator<Record>* m_pAllocator;
#endif

    size_t m_TableSize, m_ItemsCount;   // size of item table, number of added items
    size_t m_HashSize;    // size of hash table

    Record ** m_Hash;   // hash table
    //int m_Err; // 0 - ok, -1 - init by 0 size (recreate table on Add), 1 - error

    int m_Flags;
#ifdef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
    int m_AutoSqueezeLock;
#endif

public:
    enum // m_Flags
    {
        eErr1           = 0x01,
        eOk0            = 0x02,
        eNothingMask    = eErr1 | eOk0,
        eAutoSqueeze    = 0x04,
        eDefaultArgs    = 0x80000000 // Default preallocate and allocator_type
    };

protected:
    // hash function of key
    //#define ___HashFunction CMaaHashFunction
#define ___HashFunction(K) (bStandartHash ? CMaaHashFunction(K) : HashFunction(K))
    virtual _dword HashFunction(const Key &K) const noexcept
    {
        /*
          if   (sizeof(Key) == sizeof(_dword))
          {
               return *(_dword*)&K;
          }
          else
          {
               unsigned char * p = (unsigned char *)&K;
               _dword x = 0;
               for  (int i = sizeof(Key); i--;)
               {
                    x = ((x << 7) | (x >> 25)) ^ *p++;
               }
               return x;
          }
          */
        return CMaaHashFunction(K);
    }

public:

    class iterator : public CMaaDLink
    {
        friend class CMaaUnivHash_New<Key, Data, bStandartHash>;
        CMaaUnivHash_New<Key, Data, bStandartHash> * h;
        typename CMaaUnivHash_New<Key, Data, bStandartHash>::Record * r;
        size_t index;
        bool bInc;
    public:
        iterator() noexcept
        :   h(nullptr)
        {
            Init();
        }
        iterator(CMaaUnivHash_New<Key, Data, bStandartHash> &ht) noexcept
        :   h(nullptr)
        {
            CMaaDLink::Init();
            *this = ht.it();
        }
        iterator(const iterator &That) noexcept
        :   CMaaDLink(),
            h(nullptr)
        {
            CMaaDLink::Init();
            *this = That;
        }
        /*
          iterator(iterator &That)
          :    h(nullptr)
          {
               Init();
               *this = That;
          }
        */
        ~iterator() noexcept
        {
            Release();
        }
        void Release() noexcept
        {
            if  (h)
            {
                h->m_Iterators.Release(this);
                h->UnLockAutoSqueeze();
                h = nullptr;
            }
        }
        iterator & operator=(const iterator &that) noexcept
        {
            iterator &That = (iterator &)that;
            if  (this != &That)
            {
                Release();
                if  ((h = That.h))
                {
                    h->LockAutoSqueeze();
                    r = That.r;
                    index = That.index;
                    bInc = That.bInc;
                    h->m_Iterators.AddAtFront(this);
                }
            }
            return *this;
        }
        iterator & operator=(CMaaUnivHash_New<Key, Data, bStandartHash> &ht) noexcept
        {
            Release();
            *this = ht.it();
            return *this;
        }
        bool IsValid() const noexcept
        {
            return h && !bInc && r;
        }
        operator bool () const noexcept
        {
            return IsValid();
        }
        // fast, noexcept functions w/o of validity check
        const Key& ckey() const noexcept
        {
            return r->K;
        }
        Key key() noexcept(noexcept(Key(r->K))) //const
        {
            return r->K;
        }
        Data & rdata() noexcept
        {
            return r->D;
        }
        Data data() noexcept(noexcept(Data(r->D))) //const
        {
            return r->D;
        }

        const Key & ckeyEx() const
        {
            if  (!IsValid())
            {
                throw 1;
            }
            return r->K;
        }
        Key keyEx() //const
        {
            if  (!IsValid())
            {
                throw 1;
            }
            return r->K;
        }
        Data & rdataEx()
        {
            if  (!IsValid())
            {
                throw 1;
            }
            return r->D;
        }
        Data dataEx() //const
        {
            if  (!IsValid())
            {
                throw 1;
            }
            return r->D;
        }

        /*
        operator Key ()
        {
            if   (!IsValid())
            {
                throw 1;
            }
            return r->K;
        }
        Data & operator()()
        {
            if   (!IsValid())
            {
                throw 1;
            }
            return r->D;
        }
        */
        iterator operator++(int) noexcept
        {
            iterator tmp(*this);
            ++(*this);
            return tmp;
        }
        iterator operator++() noexcept
        {
            if  (h) // remark
            {
                if  (!bInc)
                {
                    Inc();
                }
                if  (bInc)
                {
                    bInc = false;
                }
                else
                {
                    Release();
                }
            }
            return *this;
        }
        bool Inc() noexcept
        {
            if  (h && r)
            {
                r = r->pNext;
                if  (!r)
                {
                    while(++index < h->m_HashSize)
                    {
                        if  ((r = h->m_Hash[index]))
                        {
                            break;
                        }
                    }
                }
                if  (r)
                {
                    bInc = true;
                    return true;
                }
            }
            Release();
            return false;
        }
        int Remove(Data * d) noexcept(noexcept(r->K == r->K) && noexcept(*d = *d)) //noexcept( noexcept(h->Remove(r->K, d)) ) // remove key, 0 - ok, 1 - not found, 2 - iterator is not valid
        {
            if  (IsValid())
            {
                return h->Remove(r->K, d);
            }
            return 2;
        }
        int Remove() noexcept(noexcept(r->K == r->K)) //noexcept( noexcept(h->Remove(r->K)) ) // remove key, 0 - ok, 1 - not found, 2 - iterator is not valid
        {
            if  (IsValid())
            {
                return h->Remove(r->K);
            }
            return 2;
        }
    };

    class AutoSqueezeLocker
    {
        //friend class CMaaUnivHash_New<Key, Data>;
        CMaaUnivHash_New<Key, Data, bStandartHash> &h;
    public:
        AutoSqueezeLocker(CMaaUnivHash_New<Key, Data, bStandartHash> &ht) noexcept
        :   h(ht)
        {
            Lock();
        }
        AutoSqueezeLocker (const AutoSqueezeLocker& That) = delete;
        AutoSqueezeLocker& operator=(const AutoSqueezeLocker& That) = delete;
        ~AutoSqueezeLocker() noexcept
        {
            UnLock();
        }
        void Lock() noexcept
        {
            h.LockAutoSqueeze();
        }
        void UnLock() noexcept
        {
            h.UnLockAutoSqueeze();
        }
    };

protected:
    CMaaDList<iterator> m_Iterators;
public:
    iterator it() noexcept
    {
        for (size_t i = 0; i < m_HashSize; i++)
        {
            if  (m_Hash[i])
            {
                iterator it;
                LockAutoSqueeze();
                it.h = this;
                it.index = i;
                it.r = m_Hash[i];
                it.bInc = false;
                m_Iterators.AddAtFront(&it);
                return it;
            }
        }
        return iterator();
    }
    void InvalidateIterators() noexcept
    {
        iterator * p;
        while((p = m_Iterators.GetFromFront()))
        {
            if (p->h)
            {
                UnLockAutoSqueeze();
                p->h = nullptr;
            }
        }
    }
    void MoveIterators(const Record * r) noexcept
    {
        iterator * n;
        for (iterator * p = m_Iterators.LookAtFront(); p; p = n)
        {
            n = m_Iterators.Next(p);
            if  (p->h && p->r == r)
            {
                p->Inc();
            }
        }
    }
    void ChangeIterators(const Record * pOld, Record * pNew) noexcept
    {
        iterator * n;
        for (iterator * p = m_Iterators.LookAtFront(); p; p = n)
        {
            n = m_Iterators.Next(p);
            if  (p->h && p->r == pOld)
            {
                p->r = pNew;
            }
        }
    }

    virtual void Swap(CMaaUnivHash_New<Key, Data, bStandartHash> &That) noexcept
    {
        CMaaSwap(m_TableSize,  That.m_TableSize);
        CMaaSwap(m_HashSize,   That.m_HashSize);
        CMaaSwap(m_ItemsCount, That.m_ItemsCount);
        CMaaSwap(m_Hash,       That.m_Hash);
#ifndef TOOLSLIB_SHARED_ALLOCATOR
        CMaaSwap(m_pAllocator, That.m_pAllocator);
#endif
        //CMaaSwap(m_Err,        That.m_Err);
        CMaaSwap(m_Flags,      That.m_Flags);
#ifdef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
        //!!!//CMaaSwap(m_AutoSqueezeLock, That.m_AutoSqueezeLock);
#endif

        CMaaDList<iterator> l1, l2;
        l1.MoveThatToTheFront(m_Iterators);
        l2.MoveThatToTheFront(That.m_Iterators);

        iterator * p;
        while((p = l1.GetFromFront()))
        {
            if  (p->h)
            {
                That.LockAutoSqueeze();
                p->h->UnLockAutoSqueeze();
                p->h = &That;
                That.m_Iterators.AddAtBack(p);
            }
        }
        while((p = l2.GetFromFront()))
        {
            if  (p->h)
            {
                LockAutoSqueeze();
                p->h->UnLockAutoSqueeze();
                p->h = this;
                m_Iterators.AddAtBack(p);
            }
        }
    }

    CMaaUnivHash_New<Key, Data, bStandartHash>& operator=(CMaaUnivHash_New<Key, Data, bStandartHash>&& That) noexcept
    {
        Swap(That);
        That.Cleanup();
        return *this;
    }

    virtual CMaaUnivHash_New<Key, Data, bStandartHash> * MakeNewTable(size_t Size, CMaaUnivHash_New<Key, Data, bStandartHash> * ptr, int Flags)//, int preallocate = 0, int allocator_type = -1)
    {
        return TL_NEW CMaaUnivHash_New<Key, Data, bStandartHash>(Size, ptr, 0, -1, Flags);//, preallocate, allocator_type, Flags);
    }

private:
    void Init(size_t Size, int Flags)
    {
        if  ( Size < 2 )
        {
            Size = 0;
        }
        Flags &= ~ eNothingMask;
        const size_t MaxSz = ((size_t)-1) / sizeof(Record *) / 2;
        m_HashSize     = (Size + Size / 10 <= MaxSz ? Size + Size / 10 : MaxSz);
        m_TableSize    = Size;
        m_ItemsCount   = 0;
        m_Hash         = Size && Size < SIZE_MAX / sizeof(void *) / 11 * 10 ? TL_NEW Record * [ m_HashSize ] : nullptr;
        if  (m_Hash)
        {
            Memzero(m_Hash, m_HashSize * sizeof(*m_Hash));
            m_Flags = Flags;
#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
            gHashTablesAllocSize += (_qword)(m_HashSize * sizeof(*m_Hash));
#endif
        }
        else
        {
            m_Flags = Flags | (Size ? eErr1 : eOk0);
        }
#ifdef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
        m_AutoSqueezeLock = 0;
#endif
    }

public:
    CMaaUnivHash_New<Key, Data, bStandartHash> & operator = (const CMaaUnivHash_New<Key, Data, bStandartHash> &That)
    {
        if  (this != &That)
        {
            iterator it((CMaaUnivHash_New<Key, Data, bStandartHash> &)That);
            Cleanup();
            for (; it; ++it)
            {
                Add(it.key(), it.data());
            }
        }
        return *this;
    }
    CMaaUnivHash_New(size_t Size = 16, CMaaUnivHash_New<Key, Data, bStandartHash> * ptr = nullptr, int iPreallocate = 0, int allocator_type = -1, int Flags = TOOLSLIB_HT_DEF_FLAG)
    {
        if (Flags & eDefaultArgs)
        {
            iPreallocate = 0;
            allocator_type = -1;
            Flags &= ~ eDefaultArgs;
        }

#ifndef TOOLSLIB_SHARED_ALLOCATOR
        m_pAllocator = nullptr;
#endif
        Init(Size, Flags);
#ifndef TOOLSLIB_SHARED_ALLOCATOR
        if  (ptr)
        {
            m_pAllocator = ptr->m_pAllocator;
        }
        if  (!m_pAllocator)
        {
            m_pAllocator = TL_NEW CMaaFixedAllocator<Record>(ptr && ptr->m_pAllocator ? ptr->m_pAllocator->GetAllocatorType() : allocator_type);
        }
        if  (m_pAllocator)
        {
            m_pAllocator->AddRefEx();
            if  ((!ptr && iPreallocate >= 0) || iPreallocate > 0)
            {
                try
                {
                    if  (!m_pAllocator->PreAllocate(Size))
                    {
                        m_Flags |= eErr1;
                    }
                }
                catch(...)
                {
                    m_pAllocator->DelRefEx();
#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
                    if (m_Hash)
                    {
                        gHashTablesAllocSize -= (_qword)(m_HashSize * sizeof(*m_Hash));
                    }
#endif
                    delete [] m_Hash;  m_Hash  = nullptr;
                    throw;
                }
            }
        }
        else
        {
            m_Flags |= eErr1;
        }
#else
        //if (!CMaaFixedAllocator<CMaaUnivHash_New<Key, Data>::Record>::CreateAddRefUl(&Record::s_pAllocator))
        if (!CMaaFixedAllocator<CMaaUnivHash_New<Key, Data, bStandartHash>::Record>::CreateAddRef(&Record::s_pAllocator))
        {
            m_Flags |= eErr1;
        }
#endif
    }

    void SetAutoSqueeze(bool b) noexcept
    {
#ifdef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
        m_Flags = b ? (m_Flags | eAutoSqueeze) : (m_Flags & ~ eAutoSqueeze);
#endif
    }
    void LockAutoSqueeze() noexcept
    {
#ifdef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
        ++m_AutoSqueezeLock;
#endif
    }
    void UnLockAutoSqueeze() noexcept
    {
#ifdef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
        --m_AutoSqueezeLock;
#endif
    }
    bool IsNeedToSqueeze() const noexcept
    {
#ifdef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
        if ((m_Flags & eAutoSqueeze) && m_AutoSqueezeLock <= 0 && m_ItemsCount <= m_TableSize / 4 && m_TableSize > 16)
        {
            return true;
        }
#else
        if (!m_Iterators.LookAtFront() && m_ItemsCount <= m_TableSize / 4 && m_TableSize > 16)
        {
            return true;
        }
#endif
        return false;
    }

    CMaaUnivHash_New(CMaaUnivHash_New<Key, Data, bStandartHash>&& That)
    {
        size_t Size = 0;
        int iPreallocate = 0;
        int allocator_type = -1;
        CMaaUnivHash_New<Key, Data, bStandartHash>* ptr = /*nullptr; // =*/ (CMaaUnivHash_New<Key, Data, bStandartHash> *) & That;

#ifndef TOOLSLIB_SHARED_ALLOCATOR
        m_pAllocator = nullptr;
#endif
        Init(Size, 0);
#ifndef TOOLSLIB_SHARED_ALLOCATOR
        if  (ptr)
        {
            m_pAllocator = ptr->m_pAllocator;
        }
        if  (!m_pAllocator)
        {
            m_pAllocator = TL_NEW CMaaFixedAllocator<Record>(ptr && ptr->m_pAllocator ? ptr->m_pAllocator->GetAllocatorType() : allocator_type);
        }
        if  (m_pAllocator)
        {
            m_pAllocator->AddRefEx();
            if  ((!ptr && iPreallocate >= 0) || iPreallocate > 0)
            {
                try
                {
                    if  (!m_pAllocator->PreAllocate(Size))
                    {
                        m_Flags |= eErr1;
                    }
                }
                catch(...)
                {
                    m_pAllocator->DelRefEx();
#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
                    if (m_Hash)
                    {
                        gHashTablesAllocSize -= (_qword)(m_HashSize * sizeof(*m_Hash));
                    }
#endif
                    delete[] m_Hash;  m_Hash = nullptr;
                    throw;
                }
            }
        }
        else
        {
            m_Flags |= eErr1;
        }
#endif
        Swap(That);
    }

    CMaaUnivHash_New(const CMaaUnivHash_New<Key, Data, bStandartHash> &That)
    {
        size_t Size = 16;
        int iPreallocate = 0;
        int allocator_type = -1;
        CMaaUnivHash_New<Key, Data, bStandartHash> * ptr = /*nullptr; // =*/ (CMaaUnivHash_New<Key, Data, bStandartHash> *)&That;

#ifndef TOOLSLIB_SHARED_ALLOCATOR
        m_pAllocator = nullptr;
#endif
        Init(Size, That.m_Flags);
#ifndef TOOLSLIB_SHARED_ALLOCATOR
        if  (ptr)
        {
            m_pAllocator = ptr->m_pAllocator;
        }
        if  (!m_pAllocator)
        {
            m_pAllocator = TL_NEW CMaaFixedAllocator<Record>(ptr && ptr->m_pAllocator ? ptr->m_pAllocator->GetAllocatorType() : allocator_type);
        }
        if  (m_pAllocator)
        {
            m_pAllocator->AddRefEx();
            if  ((!ptr && iPreallocate >= 0) || iPreallocate > 0)
            {
                try
                {
                    if  (!m_pAllocator->PreAllocate(Size))
                    {
                        m_Flags |= eErr1;
                    }
                }
                catch(...)
                {
                    m_pAllocator->DelRefEx();
#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
                    if (m_Hash)
                    {
                        gHashTablesAllocSize -= (_qword)(m_HashSize * sizeof(*m_Hash));
                    }
#endif
                    delete [] m_Hash;  m_Hash  = nullptr;
                    throw;
                }
            }
            *this = That;
        }
        else
        {
            m_Flags |= eErr1;
        }
#endif
    }

    void unite(const CMaaUnivHash_New<Key, Data, bStandartHash> & OtherTable)
    {
        iterator it((CMaaUnivHash_New<Key, Data, bStandartHash> &)OtherTable);
        for (; it; ++it)
        {
            Add(it.key(), it.data());
        }
    }
    const Data value(const Key &key, const Data &defaultValue) const
    {
        Data d = defaultValue;
        ((CMaaUnivHash_New<Key, Data, bStandartHash>&)*this).Find(key, &d);
        return d;
    }
    bool isEmpty() const noexcept
    {
        return GetItemCount() == 0;
    }

    bool IsOK() const noexcept
    {
        return !(m_Flags & eErr1);
    }

    virtual ~CMaaUnivHash_New () noexcept
    {
        InvalidateIterators();

        if  (m_ItemsCount > 0 && m_Hash)
        {
            //printf("deleting %d objects...", (int)m_ItemsCount);
            for (size_t i = 0; i < m_HashSize; ++i)
            {
                Record * n;
                for (Record* r = m_Hash[i]; r; r = n)
                {
                    n = r->pNext;
#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
                    gHashTablesAllocSize -= (_qword)(sizeof(*r));
#endif
#ifndef TOOLSLIB_SHARED_ALLOCATOR
                    r->~Record();
                    m_pAllocator->DeleteEx(r, &m_pAllocator);
#else
                    delete r;
#endif
                }
            }
        }
#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
        if (m_Hash)
        {
            gHashTablesAllocSize -= (_qword)(m_HashSize * sizeof(*m_Hash));
        }
#endif
        delete [] m_Hash;  m_Hash  = nullptr;
#ifndef TOOLSLIB_SHARED_ALLOCATOR
        if  (m_pAllocator)
        {
            m_pAllocator->DelRefEx(&m_pAllocator);
        }
#else
        // 2023+:
        Record::s_pAllocator->DelRefEx(&Record::s_pAllocator);
#endif
        m_Flags |= eErr1;
    }

    void Cleanup() noexcept
    {
        InvalidateIterators();
        if (m_ItemsCount > 0)
        {
            for (size_t i = 0; i < m_HashSize; ++i)
            {
                Record* n;
                for (Record* r = m_Hash[i]; r; r = n)
                {
                    n = r->pNext;
#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
                    gHashTablesAllocSize -= (_qword)(sizeof(*r));
#endif
#ifndef TOOLSLIB_SHARED_ALLOCATOR
                    r->~Record();
                    m_pAllocator->DeleteEx(r, &m_pAllocator);
#else
                    delete r;
#endif
                }
                m_Hash[i] = nullptr;
            }
            m_ItemsCount = 0;
        }
#ifdef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
        //Squeeze();
#endif
    }

    void Cleanup(int NewTableSize)
    {
        if (NewTableSize <= 0)
        {
            Cleanup();
        }
        else
        {
            InvalidateIterators();
            CMaaUnivHash_New<Key, Data, bStandartHash>* NewTable = MakeNewTable(NewTableSize, this, m_Flags);//, 0, m_pAllocator ? m_pAllocator->GetAllocatorType() : 0);
            if (NewTable)
            {
                Swap(*NewTable);
                delete NewTable;
            }
        }
#ifdef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
        //Squeeze();
#endif
    }

    size_t GetMaxIndex () const noexcept
    {
        return m_HashSize;
    }

    // returns 0 for success
    /*
    int FindByIndex(size_t Index, Key* K = nullptr, Data* D = nullptr) const noexcept(noexcept(*K = *K) && noexcept(*D = *D)) // obsolete
    {
        InvalidateIterators();
        if   (//Index >= 0 &&
              Index < m_HashSize)
        {
            if   (m_Hash[Index])
            {
                if   (K)
                {
                    *K = m_Hash[Index]->K;
                }
                if   ( D )
                {
                    *D = m_Hash[Index]->D;
                }
                return 0;
            }
        }
        return 1;
    }
    */

#ifndef TOOLSLIB_SHARED_ALLOCATOR
    struct RR // return record
    {
        Record*& m_pr;
        CMaaFixedAllocator<Record>* m_pAllocator;

        RR(Record*& pr, CMaaFixedAllocator<Record>* pAllocator) noexcept
        :   m_pr(pr),
            m_pAllocator(pAllocator)
        {
        }
        ~RR() noexcept
        {
            if (m_pr)
            {
#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
                gHashTablesAllocSize -= (_qword)(sizeof(*m_pr));
#endif
                //CMaaFixedAllocator<Record>::DeleteEx(m_pr, &m_pAllocator);
                m_pAllocator->DeleteEx(m_pr, &m_pAllocator);
            }
        }
    };
#else
    struct RR // return record
    {
        Record*& m_pr;

        RR(Record*& pr) noexcept
        :   m_pr(pr)
        {
        }
        ~RR() noexcept
        {
            if (m_pr)
            {
#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
                gHashTablesAllocSize -= (_qword)(sizeof(*m_pr));
#endif
                delete m_pr;
            }
        }
    };
#endif

    virtual void test__(void * /*a*/ = nullptr, void * /*b*/ = nullptr, void * /*c*/ = nullptr, int /*x1*/ = 0, int /*x2*/ = 0)
    {
    }

protected:
    void FastAddRec(Record* rec) noexcept
    {
        Record** Hash = m_Hash + ___HashFunction(rec->K) % m_HashSize;
        rec->pNext = *Hash;
        *Hash = rec;
        m_ItemsCount++;
    }

public:
    int NewMoveSwap(size_t sz)
    {
        if (sz < m_ItemsCount)
        {
            return 3; // param err
        }
        // expand table or first create on m_Err == -1
        CMaaUnivHash_New<Key, Data, bStandartHash>* NewTable = MakeNewTable(sz, this, m_Flags);//, 0, m_pAllocator ? m_pAllocator->GetAllocatorType() : 0);
        if (!NewTable || !NewTable->IsOK())
        {
            return 2; // No free elements
        }
        else
        {
            if (m_Hash)
            {
                for (size_t i = 0; i < m_HashSize; ++i)
                {
                    Record * n;
                    for (Record *r = m_Hash[i]; r; r = n)
                    {
                        n = r->pNext;
                        m_ItemsCount--;
                        NewTable->FastAddRec(r);
                    }
                    m_Hash[i] = nullptr;
                    /*
                        Record ** pHash = &m_Hash[i];
                        while (*pHash)
                        {
                            Record * r = *pHash;
                            *pHash = r->pNext;
                            m_ItemsCount--;
                            NewTable->FastAddRec(r);
                        }
                    */
                }
            }
            Swap(*NewTable);
        }
        delete NewTable;
        return 0; // ok
    }

    // Adds  element. ( Copy element to table )
    // fOverwrite: 0 - don't overwrite, > 0 - overwrite: 1 - by Data::operator=, 2 - create TL_NEW and delete old Record (exception safe), 200 - Data::~Data() and new_(ptr, Data()) (unsafe)
    // Returns 0 if success. 1 - Key alredy exists. 2 - Not enought free memory
    int Add(const Key &K, const Data &D, int fOverwrite)
    {
        InvalidateIterators();

        Record * rec = nullptr;
#ifndef TOOLSLIB_SHARED_ALLOCATOR
        RR RR_rec(rec, m_pAllocator);
#else
        RR RR_rec(rec);
#endif

#if 0
        if  (m_ItemsCount >= m_TableSize)
        {
            int Ret;
            return (Ret = NewMoveSwap(2 * m_TableSize)) ? Ret : Add(K, D, fOverwrite);
        }
#endif
        if  ((m_Flags & eErr1))
        {
            return 2;
        }

        Record** Hash = nullptr;

        if (!(m_Flags & eOk0))
        {
#ifndef TOOLSLIB_MAX_SPEED
            size_t ItemsCount = m_ItemsCount + 1;
#endif
            Hash = m_Hash + ___HashFunction(K) % m_HashSize;
            Record * This = *Hash;
            if  (This)
            {
                for (Record* prev = nullptr; This; This = This->pNext)
                {
#ifndef TOOLSLIB_MAX_SPEED
                    if  (!ItemsCount--) // integrity check failure
                    {
                        CMaaUnivHash_THROW;
                    }
#endif
                    if  (This->K == K)
                    {
                        if  (!fOverwrite)
                        {
                            return 1; // Exists
                        }
                        switch(fOverwrite)
                        {
                        case 2:
                            {
#ifndef TOOLSLIB_SHARED_ALLOCATOR
                                rec = m_pAllocator->NewEx(&m_pAllocator);
                                if  (!rec)
                                {
                                    return 2;
                                }
#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
                                gHashTablesAllocSize += (_qword)(sizeof(*rec));
#endif
                                new_(rec, Record(K, D));
#else
                                rec = TL_NEW Record(K, D);
                                if (!rec)
                                {
                                    return 2;
                                }
#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
                                gHashTablesAllocSize += (_qword)(sizeof(*rec));
#endif
#endif
                                rec->pNext = This->pNext;
                                if  (prev)
                                {
                                    prev->pNext = rec;
                                }
                                else
                                {
                                    *Hash = rec;
                                }
                                Record* r = rec;
                                rec = This;
                                ChangeIterators(This, r);
                            }
                            break;
                        case 200:
                            This->D.~Data();
                            new_(&This->D, Data(D)); // unsafe
                            break;
                        default:
                            This->D = D;
                        }
                        return 0; // ok
                    }

#ifndef TOOLSLIB_MAX_SPEED
                    if  (This == This->pNext)
                    {
                        //test__((void *)&K, (void *)&D, (void *)rec, fOverwrite);
                        CMaaUnivHash_THROW;
                    }
#endif
                    prev = This;
                }
            }
        }
        if  (m_ItemsCount >= m_TableSize) // Hash is uninitialized here, table has nothing (eOk0)
        {
            // expand table or first create on m_Err == -1
            const int Ret = NewMoveSwap(m_TableSize >= 2 ? 2 * m_TableSize : 2);
            if (Ret)
            {
                return Ret;
            }
            //return Add(K, D, fOverwrite);
            // key K is not exist
            Hash = m_Hash + ___HashFunction(K) % m_HashSize;
        }
#ifndef TOOLSLIB_SHARED_ALLOCATOR
        rec = m_pAllocator->NewEx(&m_pAllocator);
        if  (!rec)
        {
            return 2;
        }
#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
        gHashTablesAllocSize += (_qword)(sizeof(*rec));
#endif
        new_(rec, Record(K, D));
#else
        rec = TL_NEW Record(K, D);
        if (!rec)
        {
            return 2;
        }
#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
        gHashTablesAllocSize += (_qword)(sizeof(*rec));
#endif
#endif
        rec->pNext = *Hash;
        *Hash = rec;
        rec = nullptr;
        m_ItemsCount++;
        return 0;
    }

protected:
    // Adds  element. ( Copy element to table )
    // fOverwrite: 0 - don't overwrite, > 0 - overwrite: 1 - by Data::operator=, 2 - create TL_NEW and delete old Record (exception safe), 200 - Data::~Data() and new_(ptr, Data()) (unsafe)
    // Returns 0 if success. 1 - Key alredy exists. 2 - Not enought free memory
    int AddRec(Record* rec, int fOverwrite)
    {
        if (!rec)
        {
            return 3;
        }

        InvalidateIterators();

#ifndef TOOLSLIB_SHARED_ALLOCATOR
        RR RR_rec(rec, m_pAllocator);
#else
        RR RR_rec(rec);
#endif

        const Key &K = rec->K;

#if 0
        if (m_ItemsCount >= m_TableSize)
        {
            int Ret;
            if (!(Ret = NewMoveSwap(m_TableSize >= 2 ? 2 * m_TableSize : 2)))
            {
                Record* tmp = rec;
                rec = nullptr;
                Ret = AddRec(tmp, fOverwrite);
            }
            return Ret;
        }
#endif
        if ((m_Flags & eErr1))
        {
            return 2;
        }

        Record** Hash = nullptr;

        if (!(m_Flags & eOk0))
        {
#ifndef TOOLSLIB_MAX_SPEED
            size_t ItemsCount = m_ItemsCount + 1;
#endif
            Hash = m_Hash + ___HashFunction(K) % m_HashSize;
            Record *This = *Hash;
            if (This)
            {
                for (Record* prev = nullptr; This; This = This->pNext)
                {
#ifndef TOOLSLIB_MAX_SPEED
                    if (!ItemsCount--) // integrity check failure
                    {
                        CMaaUnivHash_THROW;
                    }
#endif
                    if (This->K == K)
                    {
                        if (!fOverwrite)
                        {
                            return 1; // Exists
                        }
                        Record *r = rec;
                        r->pNext = This->pNext;
                        if (prev)
                        {
                            prev->pNext = r;
                        }
                        else
                        {
                            *Hash = r;
                        }
                        rec = This;
                        ChangeIterators(This, r);
                        return 0;
                    }

#ifndef TOOLSLIB_MAX_SPEED
                    if (This == This->pNext)
                    {
                        //test__((void *)&K, (void *)&D, (void *)rec, fOverwrite);
                        CMaaUnivHash_THROW;
                    }
#endif
                    prev = This;
                }
            }
        }
        if (m_ItemsCount >= m_TableSize) // Hash is uninitialized here, table has nothing (eOk0)
        {
            int Ret;
            if ((Ret = NewMoveSwap(m_TableSize >= 2 ? 2 * m_TableSize : 2)))
            {
                return Ret;
            }
            //Record* tmp = rec;
            //rec = nullptr;
            //Ret = AddRec(tmp, fOverwrite);
            //return Ret;
            // key K is not exist
            Hash = m_Hash + ___HashFunction(K) % m_HashSize;
        }
        rec->pNext = *Hash;
        *Hash = rec;
        rec = nullptr;
        m_ItemsCount++;
        return 0;
    }

public:
    // Adds  element. ( Owerwrites it if exists )
    // Returns 0 if success. 2 - Not enought free memory
    int AddOver(const Key &K, const Data &D)
    {
        return Add(K, D, 1);
    }

    // Adds  element. ( Copy element to table )
    // Returns 0 if success. 1 - Key alredy exists. 2 - Not enought free memory, 200 - Table failure in Data::Data() or other exception
    int Add(const Key &K, const Data &D)
    {
        return Add(K, D, 0);
    }

    void insert(const Key &K, const Data &D)
    {
        Add(K, D);
    }

    // Finds element.
    // If ok: returns 0 and copy Data ( if Data != nullptr )
    int Find (const Key &K, Data *D /*= nullptr*/) const noexcept( noexcept(K==K) && noexcept(*D=*D) )
    {
        if  ((m_Flags & eNothingMask))//!m_Hash)
        {
            return 1;
        }

        Record ** Hash = m_Hash + ___HashFunction(K) % m_HashSize;

        // searching for Key
        for (Record* This = *Hash; This; This = This->pNext)
        {
            if  (This->K == K)
            {
                if  (D)
                {
                    *D = This->D;
                }
                return 0; // 0: Key was found
            }
        }
        return 1; // 1: Key was not found
    }
    // Finds element.
    // If ok: returns 0 and copy Data ( if Data != nullptr )
    int Find (const Key &K) const noexcept( noexcept(K==K) )
    {
        if  ((m_Flags & eNothingMask))//!m_Hash)
        {
            return 1;
        }

        Record** Hash = m_Hash + ___HashFunction(K) % m_HashSize;

        // searching for Key
        for (Record* This = *Hash; This; This = This->pNext)
        {
            if (This->K == K)
            {
                return 0; // 0: Key was found
            }
        }
        return 1; // 1: Key was not found
    }
    bool contains(const Key &K) const
    {
        return Find(K) == 0;
    }
    Data value(const Key &K) const
    {
        Data d;
        Find(K, &d);
        return d;
    }
    // Removes element.
    // Returns 0 if ok.
    // it is sutable to add param void * Data ( witch is nullptr by default ) where to rerurn deleted context of Data
    int Remove(const Key &K, Data * D /*= nullptr*/) 
//#ifndef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
        noexcept( noexcept(K==K) && noexcept(*D=*D) )
//#endif
    {
        if  ((m_Flags & eNothingMask))
        {
            return 1;
        }

        Record ** Hash = m_Hash + ___HashFunction(K) % m_HashSize;
        Record  * Prev = nullptr;
        // searching for Key
        for (Record *This = *Hash; This; This = This->pNext)
        {
            if  (This->K == K)
            {
                MoveIterators(This);
                if  (D)
                {
                    *D = This->D;
                }
                if  (Prev)
                {
                    Prev->pNext = This->pNext;
                }
                else
                {
                    * Hash = This->pNext;
                }
                m_ItemsCount--;
#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
                gHashTablesAllocSize -= (_qword)(sizeof(*This));
#endif
#ifndef TOOLSLIB_SHARED_ALLOCATOR
                This->~Record();
                m_pAllocator->DeleteEx(This, &m_pAllocator);
#else
                delete This;
#endif
#ifdef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
                Squeeze();
#endif
                return 0; // 0: Key was found
            }
            Prev = This;
        }
        return 1; // 1: Key was not found
    }

    // Removes element.
    // Returns 0 if ok.
    int Remove(const Key &K)
//#ifndef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
        noexcept( noexcept(K==K) )
//#endif
    {
        if  ((m_Flags & eNothingMask))
        {
            return 1;
        }

        Record ** Hash = m_Hash + ___HashFunction(K) % m_HashSize;
        Record  * Prev = nullptr;
        // searching for Key
        for (Record* This = *Hash; This; This = This->pNext)
        {
            if  (This->K == K)
            {
                MoveIterators(This);
                if  (Prev)
                {
                    Prev->pNext = This->pNext;
                }
                else
                {
                    * Hash = This->pNext;
                }
                m_ItemsCount--;
#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
                gHashTablesAllocSize -= (_qword)(sizeof(*This));
#endif
#ifndef TOOLSLIB_SHARED_ALLOCATOR
                This->~Record();
                m_pAllocator->DeleteEx(This, &m_pAllocator);
#else
                delete This;
#endif
#ifdef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
                Squeeze();
#endif
                return 0; // 0: Key was found
            }
            Prev = This;
        }
        return 1; // 1: Key was not found
    }

    int Squeeze() noexcept //noexcept(noexcept(K == K) && noexcept(*D = *D))
    {
        if (!IsNeedToSqueeze())
        {
            return -1;
        }
        const size_t NewSize = m_ItemsCount >= 1 ? 2 * m_ItemsCount : 2;
        if (NewSize >= m_TableSize)
        {
            return -1;
        }

        // squeeze table

        try
        {
            return NewMoveSwap(NewSize);
        }
        catch(...)
        {
            // No free elements, noexcept
        }
        return 2;
    }

    Data * operator [] (const Key &K) noexcept( noexcept(K==K) )
    {
        if  (!(m_Flags & eNothingMask))
        {
            Record** Hash = m_Hash + ___HashFunction(K) % m_HashSize;
            // searching for Key
            for (Record* This = *Hash; This; This = This->pNext)
            {
                if  (This->K == K)
                {
                    return &This->D;
                }
            }
        }
        return nullptr;
    }

protected:
    // returns GetItemCount()
    int EnumeratePtrs(Key ** Keys, Data ** Datas) const noexcept
    {
        Key ** p = Keys;
        for (size_t i = 0; i < m_HashSize; ++i)
        {
            // scaning all Keys
            for (Record * This = m_Hash[i]; This; This = This->pNext)
            {
                *p++ = &This->K;
                *Datas++ = &This->D;
            }
        }
        return (int)(p - Keys);
    }
    int EnumerateKeysPtrs(Key ** Keys) const noexcept
    {
        Key ** p = Keys;
        for (size_t i = 0; i < m_HashSize; ++i)
        {
            // scaning all Keys
            for (Record * This = m_Hash[i]; This; This = This->pNext)
            {
                *p++ = &This->K;
            }
        }
        return (int)(p - Keys);
    }
    int EnumerateDatasPtrs(Data ** Datas) const noexcept
    {
        Data ** p = Datas;
        for (size_t i = 0; i < m_HashSize; ++i)
        {
            // scaning all Keys
            for (Record * This = m_Hash[i]; This; This = This->pNext)
            {
                *p++ = &This->D;
            }
        }
        return (int)(p - Datas);
    }

public:
    // returns -1: invalid parameter Size, -2: Size is too small (too small arrays Keys/Datas )
    int EnumeratePtrs(int Size, Key ** Keys, Data ** Datas) const noexcept
    {
        if  (Size >= 0)
        {
            //InvalidateIterators();
#ifdef TOOLSLIB_MAX_SPEED
            if  (Size >= GetItemCount())
            {
                // super opt, unsafe
                return Keys && !Datas ? EnumerateKeysPtrs(Keys) : !Keys && Datas ? EnumerateDatasPtrs(Datas) : Keys && Datas ? EnumeratePtrs(Keys, Datas) : GetItemCount();
            }
#endif
            int j = 0;
            for (size_t i = 0; i < m_HashSize; ++i)
            {
                // scaning all Keys
                for (Record * This = m_Hash[i]; This; This = This->pNext)
                {
                    if  (j >= Size)
                    {
                        return -2;
                    }
                    if  (Keys)
                    {
                        Keys[j] = &This->K;
                    }
                    if  (Datas)
                    {
                        Datas[j] = &This->D;
                    }
                    j++;
                }
            }
            return j;
        }
        return -1;
    }

protected:
    // returns GetItemCount()
    int EnumerateKeys(Key * Keys) const noexcept( noexcept(*Keys=*Keys) )
    {
        Key * p = Keys;
        for (size_t i = 0; i < m_HashSize; ++i)
        {
            // scaning all Keys
            for (Record * This = m_Hash[i]; This; This = This->pNext)
            {
                *p++ = This->K;
            }
        }
        return (int)(p - Keys);
    }
    int EnumerateDatas(Data * Datas) const noexcept( noexcept(*Datas=*Datas) )
    {
        Data * p = Datas;
        for (size_t i = 0; i < m_HashSize; ++i)
        {
            // scaning all Keys
            for (Record * This = m_Hash[i]; This; This = This->pNext)
            {
                *p++ = This->D;
            }
        }
        return (int)(p - Datas);
    }
    int EnumerateItems(Key * Keys, Data * Datas) const noexcept( noexcept(*Keys=*Keys) && noexcept(*Datas=*Datas) )
    {
        Key * p = Keys;
        for (size_t i = 0; i < m_HashSize; ++i)
        {
            // scaning all Keys
            for (Record * This = m_Hash[i]; This; This = This->pNext)
            {
                *p++ = This->K;
                *Datas++ = This->D;
            }
        }
        return (int)(p - Keys);
    }

public:
    // returns -1: invalid parameter Size, -2: Size is too small (too small arrays Keys/Datas )
    int EnumerateItems(int Size, Key * Keys, Data * Datas) const noexcept( noexcept(*Keys=*Keys) && noexcept(*Datas=*Datas) )
    {
        if  (Size >= 0)
        {
#ifdef TOOLSLIB_MAX_SPEED
            if  (Size >= GetItemCount())
            {
                // super opt, unsafe
                return Keys && !Datas ? EnumerateKeys(Keys) : !Keys && Datas ? EnumerateDatas(Datas) : Keys && Datas ? EnumerateItems(Keys, Datas) : GetItemCount();
            }
#endif
            int j = 0;
            for (size_t i = 0; i < m_HashSize; ++i)
            {
                // scaning all Keys
                for (Record * This = m_Hash[i]; This; This = This->pNext)
                {
                    if  (Keys)
                    {
                        if  (j >= Size)
                        {
                            return -2;
                        }
                        *Keys = This->K;
                        Keys++;
                    }
                    if  (Datas)
                    {
                        if  (j >= Size)
                        {
                            return -2;
                        }
                        *Datas = This->D;
                        Datas++;
                    }
                    j++;
                }
            }
            return j;
        }
        return -1;
    }

    int GetItemCount () const noexcept
    {
        return (int)m_ItemsCount;
        //return EnumerateItems ( 0x7fffffff, nullptr, nullptr );
    }

    typedef void (*EnumerateProc)(const Key &K, Data &D, void * Param);
    typedef void (*EnumerateProcEx)(const Key &K, Data &D, CMaaUnivHash_New<Key, Data, bStandartHash> &ht, void * Param);

    void EnumerateByProc(EnumerateProc Proc, void * Param)
    {
#ifdef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
        AutoSqueezeLocker l(*this);
#endif
        Record * Next;
        for (size_t i = 0; i < m_HashSize; ++i)
        {
            // scanning all Keys
            for (Record * This = m_Hash[i]; This; This = Next)
            {
                Next = This->pNext;
                Proc(This->K, This->D, Param);
            }
        }
    }

    void EnumerateByProc(EnumerateProcEx Proc, void * Param)
    {
#ifdef TOOLSLIB_AUTO_SQUEEZE_HASH_TABLE
        AutoSqueezeLocker l(*this);
#endif
        Record * Next;
        for (size_t i = 0; i < m_HashSize; ++i)
        {
            // scanning all Keys
            for (Record * This = m_Hash[i]; This; This = Next)
            {
                Next = This->pNext;
                Proc(This->K, This->D, *this, Param);
            }
        }
    }

    template<typename Fn> void EnumerateByProc(Fn Proc)
    {
        Record * Next;
        for (size_t i = 0; i < m_HashSize; ++i)
        {
            // scanning all Keys
            for (Record * This = m_Hash[i]; This; This = Next)
            {
                Next = This->pNext;
                Proc((const Key &)(This->K), This->D);
            }
        }
    }
    static _qword GetHashTablesAllocSize() noexcept
    {
#ifdef TOOLSLIB_COLLECT_HASH_TABLES_ALLOC_SIZE
        return gHashTablesAllocSize;
#else
        return -1;
#endif
    }
};
//---------------------------------------------------------------------------
template<class Key, class Data> class CMaaUnivHash_New_KeyIsClass : public CMaaUnivHash_New<Key, Data, false>
{
    _dword HashFunction(const Key &K) const noexcept override
    {
        return K.Hash();
    }
public:
    CMaaUnivHash_New_KeyIsClass(size_t Size = 16, CMaaUnivHash_New<Key, Data, false> * ptr = nullptr, int preallocate = 0, int allocator_type = -1, int Flags = TOOLSLIB_HT_DEF_FLAG)
    :   CMaaUnivHash_New<Key, Data, false>(Size, ptr, preallocate, allocator_type, Flags)
    {
    }

    CMaaUnivHash_New<Key, Data, false> * MakeNewTable(size_t Size, CMaaUnivHash_New<Key, Data, false> * ptr, int Flags) override//, int preallocate = 0, int allocator_type = -1)
    {
        return TL_NEW CMaaUnivHash_New_KeyIsClass<Key, Data>(Size, ptr, 0, -1, Flags); // preallocate and allocator_type are ignored by (Flags & 0x80);
    }

    CMaaUnivHash_New_KeyIsClass(CMaaUnivHash_New_KeyIsClass<Key, Data>&& That)
    :   CMaaUnivHash_New<Key, Data, false>(std::move((CMaaUnivHash_New<Key, Data, false>&&)That))
    {
    }

    CMaaUnivHash_New_KeyIsClass<Key, Data> & operator=(CMaaUnivHash_New_KeyIsClass<Key, Data>&& That)
    {
        CMaaUnivHash_New<Key, Data, false>::operator=(std::move((CMaaUnivHash_New<Key, Data, false>&&)That));
        return *this;
    }
};
//---------------------------------------------------------------------------
template<class Key, class Data, bool bStandartHash> class CMaaUnivHash_NewClassPtr : public CMaaUnivHash_New<Key, Data, bStandartHash>
{
public:
    CMaaUnivHash_NewClassPtr(size_t Size = 16, CMaaUnivHash_New<Key, Data, bStandartHash> * ptr = nullptr, int preallocate = 0, int allocator_type = -1, int Flags = TOOLSLIB_HT_DEF_FLAG)
    :   CMaaUnivHash_New<Key, Data, bStandartHash>(Size, ptr, preallocate, allocator_type, Flags)
    {
    }

    CMaaUnivHash_New<Key, Data, bStandartHash> * MakeNewTable(size_t Size, CMaaUnivHash_New<Key, Data, bStandartHash> * ptr, int Flags) override//, int preallocate = 0, int allocator_type = -1)
    {
        return TL_NEW CMaaUnivHash_NewClassPtr<Key, Data, bStandartHash>(Size, ptr, 0, -1, Flags); // preallocate and allocator_type are ignored by (Flags & 0x80);
    }

    static void ObjectDeleter(Key &/*K*/, Data &D, CMaaUnivHash_New<Key, Data, bStandartHash> &/*ht*/, void * /*Param*/) noexcept
    {
        delete D;
    }

    ~CMaaUnivHash_NewClassPtr() noexcept
    {
        CMaaUnivHash_New<Key, Data, bStandartHash>::InvalidateIterators();
        EnumerateByProc(ObjectDeleter);
    }

    CMaaUnivHash_NewClassPtr(CMaaUnivHash_NewClassPtr<Key, Data, bStandartHash>&& That)
    :   CMaaUnivHash_New<Key, Data, bStandartHash>(std::move((CMaaUnivHash_New<Key, Data, bStandartHash>&&)That))
    {
    }

    CMaaUnivHash_NewClassPtr<Key, Data, bStandartHash>& operator=(CMaaUnivHash_NewClassPtr<Key, Data, bStandartHash>&& That)
    {
        CMaaUnivHash_New<Key, Data, bStandartHash>::operator=(std::move((CMaaUnivHash_New<Key, Data, bStandartHash>&&)That));
        return *this;
    }
};
//---------------------------------------------------------------------------
//#undef ___HashFunction
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// CMaaUnivHash_New2 has the same speed as CMaaUnivHash_New
//---------------------------------------------------------------------------
//#include "Hash_New2.h"
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// template<class X, X val> class CMaaAutoInitObject;
// template<class X, typename Y, Y val> class CMaaAutoInitObjectEx;
// template<class X> class CMaaForcedInitObject; // constructor with one argument
//
// Limitations: Y is a simple type, val is a integral type value
//
// Exampes of using:
//
#if 0
class IntEx
{
public:
    int x;
    IntEx(int tmp)
    :   x(tmp)
    {
    }
};

int GlobalInt = 'GLOB';

int main()
{
    CMaaAutoInitObject<bool, false> val123;
    CMaaAutoInitObjectEx<bool, bool, false> val;
    val = val123;
    val123 = val;
    CMaaAutoInitObjectEx<IntEx, int, 12345> valEx;
    CMaaAutoInitObjectEx<int, int, 12345> val2;
    CMaaAutoInitObject<int, 15> val234;
    CMaaAutoInitObject<int *, &GlobalInt/*nullptr*/> pInt;
    CMaaForcedInitObject<int *> pFInt;//(&val234);
    printf("pInt = %p, pFInt = %p, *pFInt = %d\n", (int *)pInt, (int *)pFInt, *pFInt);
    pInt = &val2;
    val2 = val234;
    printf("pInt = %p, *pInt = %d\n", (int *)pInt, *pInt);
    valEx = val234;
    ((IntEx&)valEx).x = 4567;
    printf("val2 = %d, %d, %d\n", (int)val2, (int)val2, (int)val2);
    val2 = 789;
    printf("val2 = %d\n", (int)val2);
    int x = val2;
    val2++;
    printf("x = %d, val2 = %d\n", x, val2);

    printf("\n");
    int * p = (int *)&val2;
    printf("p = %p\n", p);
    p = &val2;
    printf("p = %p\n", p);
    *p = 10;
    printf("val2 = %d\n", (int)val2);

    //long * l = val2;
    //printf("l = %p\n", l);
}
#endif

template<class X, X val> class CMaaAutoInitObject
{
    X x;
public:
    CMaaAutoInitObject()
    :   x(val)
    {
    }
    CMaaAutoInitObject(const X & _x)
    :   x(_x)
    {
    }
    /*
     typedef typename *X XX;
     XX operator->()
     {
          return *x;
     }
     const XX operator->() const
     {
          return *x;
     }
     */
    operator X & () noexcept
    {
        return x;
    }
    operator const X & () const noexcept
    {
        return x;
    }
    X * operator &() noexcept
    {
        return &x;
    }
    const X * operator &() const noexcept
    {
        return &x;
    }
    template<class Z> X & operator = (Z & z)
    {
        x = z;
        return x;
    }
    template<class Z> X & operator = (const Z & z)
    {
        x = z;
        return x;
    }
};

template<class X> class CMaaAutoInitNullPointer
{
    X x;
public:
    CMaaAutoInitNullPointer() noexcept
    :   x(nullptr)
    {
    }
    CMaaAutoInitNullPointer(const X & _x)
    :   x(_x)
    {
    }
    /*
     typedef typename *X XX;
     XX operator->()
     {
          return *x;
     }
     const XX operator->() const
     {
          return *x;
     }
     */
    operator X & () noexcept
    {
        return x;
    }
    operator const X & () const noexcept
    {
        return x;
    }
    X * operator &() noexcept
    {
        return &x;
    }
    const X * operator &() const noexcept
    {
        return &x;
    }
    template<class Z> operator Z & ()
    {
        return static_cast<Z &>(x);
    }
    template<class Z> operator const Z & () const
    {
        return static_cast<const Z &>(x);
    }
    template<class Z> X & operator = (Z & z)
    {
        x = z;
        return x;
    }
    template<class Z> X & operator = (const Z & z)
    {
        x = z;
        return x;
    }
};

template<class X, typename Y, Y val> class CMaaAutoInitObjectEx
{
    X x;
public:
    CMaaAutoInitObjectEx()
    :   x(val)
    {
    }
    operator X & () noexcept
    {
        return x;
    }
    operator const X & () const noexcept
    {
        return x;
    }
    X * operator-> ()
    {
        return *x;
    }
    const X * operator-> () const
    {
        return *x;
    }
    X * operator &() noexcept
    {
        return &x;
    }
    const X * operator &() const noexcept
    {
        return &x;
    }
    template<class Z> operator Z & ()
    {
        return static_cast<Z &>(x);
    }
    template<class Z> operator const Z & () const
    {
        return static_cast<const Z &>(x);
    }
    template<class Z> X & operator = (Z & z)
    {
        x = z;
        return x;
    }
    template<class Z> X & operator = (const Z & z)
    {
        x = z;
        return x;
    }
};

template<class X> class CMaaForcedInitObject
{
    X x;
public:
    template<class Z> CMaaForcedInitObject(Z & val)
    :   x(val)
    {
    }
    template<class Z> CMaaForcedInitObject(const Z & val)
    :   x(val)
    {
    }
    X * operator-> ()
    {
        return *x;
    }
    const X * operator-> () const
    {
        return *x;
    }
    operator X & () noexcept
    {
        return x;
    }
    operator const X & () const noexcept
    {
        return x;
    }
    X * operator &() noexcept
    {
        return &x;
    }
    const X * operator &() const noexcept
    {
        return &x;
    }
    template<class Z> operator Z & ()
    {
        return static_cast<Z &>(x);
    }
    template<class Z> operator const Z & () const
    {
        return static_cast<const Z &>(x);
    }
    template<class Z> X & operator = (Z & z)
    {
        x = z;
        return x;
    }
    template<class Z> X & operator = (const Z & z)
    {
        x = z;
        return x;
    }
};

//---------------------------------------------------------------------------
template < class Key, class Data > class CMaaUnivHash_Fast
{
    struct Record
    {
        Record * pNext;
        Key  K;
        Data D;
    };
    int  m_TableSize;   // size of item table
    int  m_HashSize;    // size of hash table

    Record * m_FreeList,   // list of free items
    * m_Table,      // table of items
    ** m_Hash;      // hash table
    bool fOK;

protected:
    // hash function of key
    virtual _dword HashFunction ( const Key & K ) const noexcept
    {
        if constexpr (sizeof(Key) == sizeof(_dword))
        {
            return *(_dword *) &K;
        }
#ifdef TRY_HF8_OPT
        else if constexpr (sizeof(Key) == 2 * sizeof(_dword))
        {
            //_dword x = *(_dword*)&K;
            //return ((x << 7) | (x >> 25)) ^ *(1 + (_dword*)&K);
            return *((_dword*)&K) ^ *(1 + (_dword*)&K);
            //return *(1 + (_dword*)&K) ^ *(_dword*)&K;
        }
#endif
        else
        {
            unsigned char * p = ( unsigned char * ) &K;
            _dword x = 0;
            //for ( int i = sizeof ( Key ); i--; )
            //{
            //    x = ((x << 7) | (x >> 25)) ^ *p++;
            //}
#ifdef TRY_HF_OPT
            for (int i = (int)(sizeof(Key)) >> _dword_shift; i--; )
            {
                x = ((x << 7) | (x >> 25)) ^ *(_dword *)p;
                p += sizeof(_dword);
            }
            for (int i = ((int)(sizeof(Key)) & _dword_mask); i--; )
            {
                x = ((x << 7) | (x >> 25)) ^ *p++;
            }
#else
            for (int i = (int)sizeof(Key); i--; )
            {
                x = ((x << 7) | (x >> 25)) ^ *p++;
            }
#endif
            return x;
        }
    }

public:

    class iterator : public CMaaDLink
    {
        friend class CMaaUnivHash_Fast<Key, Data>;
        CMaaUnivHash_Fast<Key, Data> * h;
        typename CMaaUnivHash_Fast<Key, Data>::Record * r;
        int index;
        bool bInc;
    public:
        iterator()
        :   h(nullptr)
        {
            Init();
        }
        iterator(CMaaUnivHash_Fast<Key, Data> &ht)
        :   h(nullptr)
        {
            Init();
            *this = ht.it();
        }
        iterator(const iterator &That)
        :   h(nullptr)
        {
            Init();
            *this = That;
        }
        /*
          iterator(iterator &That)
          :    h(nullptr)
          {
               Init();
               *this = That;
          }
          */
        ~iterator() noexcept
        {
            Release();
        }
        void Release() noexcept
        {
            if  (h)
            {
                h->m_Iterators.Release(this);
                h = nullptr;
            }
        }
        iterator & operator=(const iterator &that)
        {
            iterator &That = (iterator &)that;
            if  (this != &That)
            {
                Release();
                if  ((h = That.h))
                {
                    r = That.r;
                    index = That.index;
                    bInc = That.bInc;
                    h->m_Iterators.AddAtFront(this);
                }
            }
            return *this;
        }
        iterator & operator=(CMaaUnivHash_Fast<Key, Data> &ht)
        {
            Release();
            *this = ht.it();
            return *this;
        }
        bool IsValid() const noexcept
        {
            return h && !bInc && r;
        }
        operator bool () const noexcept
        {
            return IsValid();
        }
        const Key & ckey() noexcept
        {
            if  (!IsValid())
            {
                throw 1;
            }
            return r->K;
        }
        Key key()
        {
            if  (!IsValid())
            {
                throw 1;
            }
            return r->K;
        }
        Data & rdata() noexcept
        {
            if  (!IsValid())
            {
                throw 1;
            }
            return r->D;
        }
        Data data()
        {
            if  (!IsValid())
            {
                throw 1;
            }
            return r->D;
        }
        /*
          operator Key ()
          {
               if   (!IsValid())
               {
                    throw 1;
               }
               return r->K;
          }
          Data & operator()()
          {
               if   (!IsValid())
               {
                    throw 1;
               }
               return r->D;
          }
          */
        iterator operator++(int)
        {
            iterator tmp(*this);
            ++(*this);
            return tmp;
        }
        iterator operator++()
        {
            if  (h) // remark
            {
                if  (!bInc)
                {
                    Inc();
                }
                if  (bInc)
                {
                    bInc = false;
                }
                else
                {
                    Release();
                }
            }
            return *this;
        }
        bool Inc()
        {
            if  (h && r)
            {
                r = r->pNext;
                if  (!r)
                {
                    while(index < h->m_HashSize - 1 && !(r = h->m_Hash[++index]))
                    {
                    }
                }
                if  (r)
                {
                    bInc = true;
                    return true;
                }
            }
            Release();
            return false;
        }
        int Remove(Data * d = nullptr) // remove key, 0 - ok, 1 - not found, 2 - iterator is not valid
        {
            if  (IsValid())
            {
                return h->Remove(r->K, d);
            }
            return 2;
        }
    };
protected:
    CMaaDList<iterator> m_Iterators;
public:
    iterator it() noexcept
    {
        for (int i = 0; i < m_HashSize; i++)
        {
            if  (m_Hash[i])
            {
                iterator it;
                it.h = this;
                it.index = i;
                it.r = m_Hash[i];
                it.bInc = false;
                m_Iterators.AddAtFront(&it);
                return it;
            }
        }
        return iterator();
    }
    void InvalidateIterators() noexcept
    {
        iterator * p;
        while((p = m_Iterators.GetFromFront()))
        {
            p->h = nullptr;
        }
    }
    void MoveIterator(Record * r) noexcept
    {
        iterator * n;
        for (iterator * p = m_Iterators.LookAtFront(); p; p = n)
        {
            n = m_Iterators.Next(p);
            if  (p->h && p->r == r)
            {
                p->Inc();
            }
        }
    }

    virtual void Swap ( CMaaUnivHash_Fast < Key, Data > & That ) noexcept
    {
        CMaaSwap ( m_TableSize, That.m_TableSize );
        CMaaSwap ( m_HashSize,  That.m_HashSize );
        CMaaSwap ( m_FreeList,  That.m_FreeList );
        CMaaSwap ( m_Table,     That.m_Table );
        CMaaSwap ( m_Hash,      That.m_Hash );
        CMaaSwap ( fOK,         That.fOK );
        CMaaDList<iterator> l1, l2;
        l1.MoveThatToTheFront(m_Iterators);
        l2.MoveThatToTheFront(That.m_Iterators);
        iterator * p;
        while((p = l1.GetFromFront()))
        {
            p->h = &That;
            That.m_Iterators.AddAtBack(p);
        }
        while((p = l2.GetFromFront()))
        {
            p->h = this;
            m_Iterators.AddAtBack(p);
        }
    }

    virtual CMaaUnivHash_Fast < Key, Data > * MakeNewTable (size_t Size, CMaaUnivHash_Fast<Key, Data> * ptr = nullptr, int Flags = 0)
    {
        return TL_NEW CMaaUnivHash_Fast < Key, Data > ((int)Size, ptr, Flags);
    }

    CMaaUnivHash_Fast(int Size = 16, CMaaUnivHash_Fast * /*ptr*/ = nullptr, int Flags = 0)
    {
        if  ( Size < 2 )
        {
            Size = 2;
        }
        m_HashSize     = Size + Size / 10;
        m_TableSize    = Size;
        m_Table        = Size < SIZE_MAX / sizeof(Record) ? TL_NEW Record [ m_TableSize ] : nullptr;
        m_Hash         = Size < SIZE_MAX / sizeof(void*) / 11 * 10 ? TL_NEW Record * [ m_HashSize ] : nullptr;
        if  ( m_Table && m_Hash )
        {
            fOK = true;
            // Initializing free list
            Record * p =  m_Table + m_TableSize - 1;
            p->pNext = nullptr;
            for ( int i = m_TableSize - 1; i; i--, p-- )
            {
                ( p - 1 ) -> pNext = p; // m_Table [ i - 1 ].Next = & m_Table [ i ];
            }
            m_FreeList = m_Table;
            Memzero ( m_Hash, m_HashSize * sizeof ( * m_Hash ) );
        }
        else
        {
            delete [] m_Hash;  m_Hash  = nullptr;
            delete [] m_Table; m_Table = nullptr;
            fOK = false;
        }
    }

    bool IsOK () noexcept
    {
        return fOK;
    }

    virtual ~CMaaUnivHash_Fast () noexcept
    {
        InvalidateIterators();
        delete [] m_Hash;  m_Hash  = nullptr;
        delete [] m_Table; m_Table = nullptr;
    }

    void Cleanup ( int NewTableSize = 0 )
    {
        InvalidateIterators();
        CMaaUnivHash_Fast < Key, Data > * NewTable = MakeNewTable(NewTableSize ? NewTableSize : m_TableSize, this, 0);
        if  ( NewTable )
        {
            Swap ( *NewTable );
            delete NewTable;
        }
    }

    int GetMaxIndex () const noexcept
    {
        return m_HashSize;
    }

    // returns 0 for success
    int FindByIndex ( int Index, Key * K = nullptr, Data * D = nullptr ) const noexcept( noexcept(*K=*K) && noexcept(*D=*D) )
    {
        InvalidateIterators();
        if  ( Index >= 0 && Index < m_HashSize )
        {
            if  ( m_Hash [ Index ] )
            {
                if  ( K )
                {
                    *K = m_Hash [ Index ] -> K;
                }
                if  ( D )
                {
                    *D = m_Hash [ Index ] -> D;
                }
                return 0;
            }
        }
        return 1;
    }

    // Adds  element. ( Copy element to table )
    // Returns 0 if success. 1 - Key alredy exists. 2 - Not enought free memory
    int Add    ( const Key & K, const Data & D, int fOverwrite = 0 )
    {
        InvalidateIterators();

        int Ret = 0; // 0: IsOk, 1,2: IsFail
        Record * Free = m_FreeList;
        Record * This;
        if  ( ! Free )
        {
            CMaaUnivHash_Fast < Key, Data > * NewTable = MakeNewTable(2 * m_TableSize, this, 0);
            if  ( !NewTable || !NewTable->IsOK () )
            {
                Ret = 2; // No free elements
            }
            else
            {
                This = m_Table;
                for ( int i = m_TableSize; i ; i-- )
                {
                    NewTable->Add ( This -> K, This -> D );
                    This++;
                }
                Ret = NewTable->Add ( K, D, fOverwrite );
                Swap ( *NewTable );
                delete NewTable;
            }
        }
        else
        {
            Record ** Hash = m_Hash + HashFunction ( K ) % ( _dword ) m_HashSize;
            This = * Hash;
            if  ( ! This )
            {
                // Creating TL_NEW node
                * Hash = Free;
                m_FreeList = Free -> pNext;
                Free -> pNext = nullptr;
                Free -> K = K;
                Free -> D = D;
            }
            else
            {
                // searching if Key alredy exists
                for ( ; This; This = This -> pNext )
                {
                    if  ( This -> K == K )
                    {
                        if  ( ! fOverwrite )
                        {
                            Ret = 1; // Key alredy exists
                            break;
                        }
                        This -> D = D;
                        return 0;
                    }
                }
                if  ( ! Ret )
                {
                    m_FreeList = Free -> pNext;
                    Free -> pNext = *Hash;
                    * Hash = Free;
                    Free -> K = K;
                    Free -> D = D;
                }
            }
        }
        return Ret;

    }

    // Adds  element. ( Owerwrites it if exists )
    // Returns 0 if success. 2 - Not enought free memory
    int AddOver ( const Key & K, const Data & D )
    {
        return Add ( K, D, 1 );
    }

    // Finds element.
    // If ok: returns 0 and copy Data ( if Data != nullptr )
    int Find ( const Key & K, Data * D /*= nullptr*/ ) const noexcept( noexcept(K==K) && noexcept(*D=*D) )
    {
        int Ret = 1; // 0: IsOk, 1: Key was not found

        if  (!m_Table || !m_Hash)
        {
            static int aa = 0;
            aa++;
            return 1;
        }
        Record ** Hash = m_Hash + HashFunction ( K ) % ( _dword ) m_HashSize;
        Record  * This = * Hash;
        if  ( This )
        {
            // searching for Key
            for ( ; This; This = This -> pNext )
            {
                if  ( This -> K == K )
                {
                    if  ( D )
                    {
                        *D = This -> D;
                    }
                    Ret = 0; // Key was found
                    break;
                }
            }
        }
        return Ret;
    }

    // Finds element.
    // If ok: returns 0
    int Find ( const Key & K ) const noexcept( noexcept(K==K) )
    {
        int Ret = 1; // 0: IsOk, 1: Key was not found

        if  (!m_Table || !m_Hash)
        {
            static int aa = 0;
            aa++;
            return 1;
        }
        Record ** Hash = m_Hash + HashFunction ( K ) % ( _dword ) m_HashSize;
        Record  * This = * Hash;
        if  ( This )
        {
            // searching for Key
            for ( ; This; This = This -> pNext )
            {
                if  ( This -> K == K )
                {
                    Ret = 0; // Key was found
                    break;
                }
            }
        }
        return Ret;
    }

    // Removes element.
    // Returns 0 if ok.
    // it is sutable to add param void * Data ( witch is nullptr by default ) where to rerurn deleted context of Data
    int Remove ( const Key & K, Data * D /*= nullptr*/ ) noexcept( noexcept(K==K) && noexcept(*D=*D) )
    {
        int Ret = 1; // 0: IsOk, 1: Key was not found

        Record ** Hash = m_Hash + HashFunction ( K ) % ( _dword ) m_HashSize;
        Record  * This = * Hash, * Prev = nullptr;
        if  ( This )
        {
            // searching for Key
            for ( ; This; This = This -> pNext )
            {
                if  ( This -> K == K )
                {
                    MoveIterator(This);
                    if  ( D )
                    {
                        *D = This -> D;
                    }
                    if  ( Prev )
                    {
                        Prev -> pNext = This -> pNext;
                    }
                    else
                    {
                        * Hash = This -> pNext;
                    }
                    This -> pNext = m_FreeList;
                    m_FreeList = This;
                    Ret = 0; // Key was found
                    break;
                }
                Prev = This;
            }
        }
        return Ret;
    }

    // Removes element.
    // Returns 0 if ok.
    int Remove ( const Key & K ) noexcept( noexcept(K==K) )
    {
        int Ret = 1; // 0: IsOk, 1: Key was not found

        Record ** Hash = m_Hash + HashFunction ( K ) % ( _dword ) m_HashSize;
        Record  * This = * Hash, * Prev = nullptr;
        if  ( This )
        {
            // searching for Key
            for ( ; This; This = This -> pNext )
            {
                if  ( This -> K == K )
                {
                    MoveIterator(This);
                    if  ( Prev )
                    {
                        Prev -> pNext = This -> pNext;
                    }
                    else
                    {
                        * Hash = This -> pNext;
                    }
                    This -> pNext = m_FreeList;
                    m_FreeList = This;
                    Ret = 0; // Key was found
                    break;
                }
                Prev = This;
            }
        }
        return Ret;
    }

    Data * operator [] ( const Key & K ) noexcept
    {
        Record ** Hash = m_Hash + HashFunction ( K ) % ( _dword ) m_HashSize;
        Record  * This = * Hash;
        if  ( This )
        {
            // searching for Key
            for ( ; This; This = This -> pNext )
            {
                if  ( This -> K == K )
                {
                    return & This -> D;
                }
            }
        }
        return nullptr;
    }

    // returns -1: invalid parameter Size, -2: Size is too small (too small arrays Keys/Datas )
    int EnumeratePtrs ( int Size, Key ** Keys, Data ** Datas ) const noexcept
    {
        if  ( Size >= 0 )
        {
            InvalidateIterators();

            int j = 0;
            for ( int i = 0; i < m_HashSize; i++ )
            {
                Record * This = m_Hash [ i ];
                if  ( This )
                {
                    // scaning all Keys
                    for ( ; This; This = This -> pNext )
                    {
                        if  ( j >= Size )
                        {
                            return -2;
                        }
                        if  ( Keys )
                        {
                            Keys  [ j ] = & This -> K;
                        }
                        if  ( Datas )
                        {
                            Datas [ j ] = & This -> D;
                        }
                        j++;
                    }
                }
            }
            return j;
        }
        return -1;
    }

    // returns -1: invalid parameter Size, -2: Size is too small (too small arrays Keys/Datas )
    int EnumerateItems ( int Size, Key * Keys, Data * Datas ) const noexcept( noexcept(*Keys==*Keys) && noexcept(*Datas=*Datas) )
    {
        if  ( Size >= 0 )
        {
            int j = 0;
            for ( int i = 0; i < m_HashSize; i++ )
            {
                Record * This = m_Hash [ i ];
                if  ( This )
                {
                    // scaning all Keys
                    for ( ; This; This = This -> pNext )
                    {
                        if  ( Keys )
                        {
                            if  ( j >= Size )
                            {
                                return -2;
                            }
                            * Keys = This -> K;
                            Keys++;
                        }
                        if  ( Datas )
                        {
                            if  ( j >= Size )
                            {
                                return -2;
                            }
                            * Datas = This -> D;
                            Datas++;
                        }
                        j++;
                    }
                }
            }
            return j;
        }
        return -1;
    }

    int GetItemCount () const noexcept
    {
        return EnumeratePtrs ( 0x7fffffff, nullptr, nullptr );
    }

    typedef void ( *EnumerateProc )( Key & K, Data & D, void * Param );
    typedef void ( *EnumerateProcEx )( Key & K, Data & D, CMaaUnivHash_Fast < Key, Data > & ht, void * Param );

    void EnumerateByProc ( EnumerateProc Proc, void * Param = nullptr )
    {
        for ( int i = 0; i < m_HashSize; i++ )
        {
            Record * This = m_Hash [ i ];
            if  ( This )
            {
                // scanning all Keys
                Record * Next;
                for ( ; This; This = Next )
                {
                    Next = This -> pNext;
                    Proc ( This -> K, This -> D, Param );
                }
            }
        }
    }

    void EnumerateByProc ( EnumerateProcEx Proc, void * Param = nullptr )
    {
        for ( int i = 0; i < m_HashSize; i++ )
        {
            Record * This = m_Hash [ i ];
            if  ( This )
            {
                // scanning all Keys
                Record * Next;
                for ( ; This; This = Next )
                {
                    Next = This -> pNext;
                    Proc ( This -> K, This -> D, *this, Param );
                }
            }
        }
    }
};
//---------------------------------------------------------------------------
template < class Key, class Data > class CMaaUnivHash_Fast_KeyIsClass : public CMaaUnivHash_Fast < Key, Data >
{
    _dword HashFunction ( const Key & K ) const noexcept override
    {
        return K.Hash ();
    }
public:
    CMaaUnivHash_Fast_KeyIsClass(int Size = 16, CMaaUnivHash_Fast<Key, Data> * ptr = nullptr, int Flags = 0)
    :   CMaaUnivHash_Fast < Key, Data >(Size, ptr, Flags)
    {
    }
    CMaaUnivHash_Fast < Key, Data > * MakeNewTable(size_t Size, CMaaUnivHash_Fast<Key, Data> * ptr = nullptr, int Flags = 0) override
    {
        return TL_NEW CMaaUnivHash_Fast_KeyIsClass < Key, Data > ((int)Size, ptr, Flags);
    }
};
//---------------------------------------------------------------------------
template < class Key, class Data > class CMaaUnivHash_FastClassPtr : public CMaaUnivHash_Fast < Key, Data >
{
public:
    CMaaUnivHash_FastClassPtr ( int Size = 16, CMaaUnivHash_Fast<Key, Data> * ptr = nullptr, int Flags = 0)
    :   CMaaUnivHash_Fast < Key, Data > (Size, ptr, Flags)
    {
    }

    static void ObjectDeleter ( Key & /*K*/, Data & D, CMaaUnivHash_Fast < Key, Data > & /*ht*/, void * /*Param*/ ) noexcept
    {
        delete D;
    }

    ~CMaaUnivHash_FastClassPtr ()
    {
        CMaaUnivHash_Fast<Key, Data>::InvalidateIterators();
        EnumerateByProc ( ObjectDeleter );
    }
};
//---------------------------------------------------------------------------
class CMaa256Bits
{
    unsigned char m[256 / 8];
public:
    CMaa256Bits() noexcept
    {
        Clear();
    }
    CMaa256Bits(const CMaa256Bits &That) noexcept
    {
        *this = That;
    }
    CMaa256Bits(const char* ptr, int len) noexcept
    {
        Clear();
        for (int i = 0; i < len; i++)
        {
            Set(ptr[i]);
        }
    }
    CMaa256Bits(const unsigned char* ptr, int len) noexcept
    {
        Clear();
        for (int i = 0; i < len; i++)
        {
            Set(ptr[i]);
        }
    }
    ~CMaa256Bits()
    {
    }
    CMaa256Bits& operator=(const CMaa256Bits& That) noexcept
    {
        memcpy(m, That.m, sizeof(m));
        return *this;
    }
    bool operator==(const CMaa256Bits& That) noexcept
    {
        return !memcmp(m, That.m, sizeof(m));
    }
    bool operator!=(const CMaa256Bits& That) noexcept
    {
        return memcmp(m, That.m, sizeof(m));
    }
    void Set() noexcept
    {
        memset(m, -1, sizeof(m));
    }
    void Set(char c) noexcept
    {
        m[((unsigned char)c) >> 3] |= (1 << (c & 7));
    }
    void Set(unsigned char c) noexcept
    {
        m[c >> 3] |= (1 << (c & 7));
    }
    void Set(unsigned char c0, unsigned char c1) noexcept
    {
        if (c0 <= c1)
        {
            const int idx0 = (c0 >> 3);
            const int idx1 = (c1 >> 3);
            const unsigned char m0 = (0xff << (c0 & 7));
            const unsigned char m1 = (0xff >> (7 - (c1 & 7)));
            if (idx0 == idx1)
            {
                m[idx0] |= (m0 & m1);
            }
            else
            {
                m[idx0] |= m0;
                memset(m + idx0 + 1, -1, idx1 - idx0 - 1);
                m[idx1] |= m1;
            }
        }
    }
    void Set(char c0, char c1) noexcept
    {
        Set((unsigned char)c0, (unsigned char)c1);
    }
    bool Test(char c) const noexcept
    {
        return (m[((unsigned char)c) >> 3] & (1 << (c & 7)));
    }
    bool Test(unsigned char c) const noexcept
    {
        return (m[c >> 3] & (1 << (c & 7)));
    }
    void Clear() noexcept
    {
        memset(m, 0, sizeof(m));
    }
    void Clear(char c) noexcept
    {
        m[((unsigned char)c) >> 3] &= ~(1 << (c & 7));
    }
    void Clear(unsigned char c) noexcept
    {
        m[c >> 3] &= ~(1 << (c & 7));
    }
#if 0
    void Clear(unsigned char c0, unsigned char c1) noexcept // v. invert
    {
        if (c0 <= c1)
        {
            const int idx0 = (c0 >> 3);
            const int idx1 = (c1 >> 3);
            const unsigned char m0 = (0xff << (c0 & 7));
            const unsigned char m1 = (0xff >> (7 - (c1 & 7)));
            if (idx0 == idx1)
            {
                m[idx0] &= ~(m0 & m1);
            }
            else
            {
                m[idx0] &= ~ m0;
                memset(m + idx0 + 1, 0, idx1 - idx0 - 1);
                m[idx1] &= ~ m1;
            }
        }
    }
#else
    void Clear(unsigned char c0, unsigned char c1) noexcept // v. direct
    {
        if (c0 <= c1)
        {
            const int idx0 = (c0 >> 3);
            const int idx1 = (c1 >> 3);
            const unsigned char m0 = (0xff >> (8 - (c0 & 7)));
            const unsigned char m1 = (0xff << (1 + (c1 & 7)));
            if (idx0 == idx1)
            {
                m[idx0] &= (m0 | m1);
            }
            else
            {
                m[idx0] &= m0;
                memset(m + idx0 + 1, 0, idx1 - idx0 - 1);
                m[idx1] &= m1;
            }
        }
    }
#endif
    void Clear(char c0, char c1) noexcept
    {
        Clear((unsigned char)c0, (unsigned char)c1);
    }
    void Invert() noexcept
    {
        for (int i = 0; i < (int)(sizeof(m) / sizeof(_qword)); i++)
        {
            *(i + (_qword *)m) ^= (_qword)-1;
        }
    }
    CMaa256Bits& operator|=(const CMaa256Bits& That) noexcept
    {
        for (int i = 0; i < (int)(sizeof(m) / sizeof(_qword)); i++)
        {
            *(i + (_qword*)m) |= *(i + (_qword*)That.m);
        }
        return *this;
    }
    CMaa256Bits& operator&=(const CMaa256Bits& That) noexcept
    {
        for (int i = 0; i < (int)(sizeof(m) / sizeof(_qword)); i++)
        {
            *(i + (_qword*)m) &= *(i + (_qword*)That.m);
        }
        return *this;
    }
    CMaa256Bits& operator^=(const CMaa256Bits& That) noexcept
    {
        for (int i = 0; i < (int)(sizeof(m) / sizeof(_qword)); i++)
        {
            *(i + (_qword*)m) ^= *(i + (_qword*)That.m);
        }
        return *this;
    }
    char* ToText(char* p257) const noexcept
    {
        for (int i = 0; i < 256; i++)
        {
            p257[i] = Test((unsigned char)i) ? '1' : '.';
        }
        p257[256] = '\0';
        return p257;
    }
};
//---------------------------------------------------------------------------

#endif // __MAARF_MAATL_H
